Issue
Here we have an in-out animation using css inside of a vue3 application.
If we look at this outside of our vue application in a plain html + css + js instance we can see that this is easily achievable when using requestAnimationFrame()
document.getElementById('toggleButton').addEventListener('click', function() {
var rectangle = document.getElementById('myRectangle');
if (rectangle.classList.contains('animation-in')) {
rectangle.classList.remove('animation-in');
requestAnimationFrame(() => {rectangle.classList.add('animation-out');})
} else {
rectangle.classList.remove('animation-out');
requestAnimationFrame(() => {rectangle.classList.add('animation-in');})
}
});
#myRectangle {
width: 100px;
height: 150px;
background-color: green;
margin: 20px;
transform: scale(0);
}
.animation-out {
animation-duration: 4s;
animation-timing-function: ease;
animation-direction: normal;
animation-fill-mode: forwards;
animation-name: scale-easeInOutBounce;
}
.animation-in {
animation-duration: 4s;
animation-timing-function: ease;
animation-direction: reverse;
animation-fill-mode: forwards;
animation-name: scale-easeInOutBounce;
}
@keyframes scale-easeInOutBounce {
0% { transform: scale(1); }
2% { transform: scale(0.99); }
4% { transform: scale(1); }
10% { transform: scale(0.97); }
14% { transform: scale(0.99); }
22% { transform: scale(0.88); }
32% { transform: scale(0.99); }
42% { transform: scale(0.6); }
50% { transform: scale(0.5); }
58% { transform: scale(0.4); }
68% { transform: scale(0.01); }
78% { transform: scale(0.12); }
86% { transform: scale(0.01); }
90% { transform: scale(0.03); }
96% { transform: scale(0); }
98% { transform: scale(0.01); }
100% { transform: scale(0); }
}
<!DOCTYPE html>
<html>
<head>
<title>Rectangle Animation</title>
</head>
<body>
<div id="myRectangle"></div>
<button id="toggleButton">Toggle Animation</button>
</body>
</html>
The area where I would appreciate help and guidance, is applying a working solution within vue. The challenge is to integrate it within Vue's reactivity and lifecycle hooks.
As we may know, requestAnimationFrame() is a JavaScript function that tells the browser to perform an animation and requests that the browser calls a specified function to update an animation before the next repaint. The method takes a callback function as an argument, which is called before the next repaint. This callback is where you'd typically update your animation logic. It's more efficient and smoother for animations than setTimeout or setInterval, especially for web animations.
Here is a vue instance of the project that I need some help with:
https://jsfiddle.net/midnightstudios/fmz172wr/
<!DOCTYPE html>
<html>
<head>
<script src="https://unpkg.com/vue@next"></script>
<style>
.element {
width: 100px;
height: 150px;
background-color: green;
margin: 20px;
transform: scale(0);
}
.animation-out {
animation-duration: 4s;
animation-timing-function: ease; /*linear*/
animation-delay: 0s;
animation-iteration-count: 1;
animation-direction: normal;
animation-fill-mode: forwards;
animation-play-state: running;
animation-name: scale-easeInOutBounce;
animation-timeline: auto;
animation-range-start: normal;
animation-range-end: normal;
}
.animation-in {
animation-duration: 4s;
animation-timing-function: ease;
animation-delay: 0s;
animation-iteration-count: 1;
animation-direction: reverse;
animation-fill-mode: forwards;
animation-play-state: running;
animation-name: scale-easeInOutBounce;
animation-timeline: auto;
animation-range-start: normal;
animation-range-end: normal;
}
@keyframes scale-easeInOutBounce {
0% { transform: scale(1); }
2% { transform: scale(0.99); }
4% { transform: scale(1); }
10% { transform: scale(0.97); }
14% { transform: scale(0.99); }
22% { transform: scale(0.88); }
32% { transform: scale(0.99); }
42% { transform: scale(0.6); }
50% { transform: scale(0.5); }
58% { transform: scale(0.4); }
68% { transform: scale(0.01); }
78% { transform: scale(0.12); }
86% { transform: scale(0.01); }
90% { transform: scale(0.03); }
96% { transform: scale(0); }
98% { transform: scale(0.01); }
100% { transform: scale(0); }
}
</style>
<script src="https://unpkg.com/vue@next"></script>
<script>
const { createApp, ref, reactive, computed, watch } = Vue;
</script>
</head>
<body>
<div id="app"></div>
<template id="app-template">
<div :class="classes">
</div>
<button @click="trigger()" style="padding:5px;margin:10px;width:200px;height:30px; position: absolute; bottom: 10px; left: 50px;">{{triggerLabel}}</button>
</template>
<script>
const App = {
template: '#app-template',
components: {
},
setup() {
const props = {
// Define some reactive data
active: ref(false),
};
return {...props};
},
created(){
},
mounted() {
},
watch: {
},
computed: {
classes(){
const animationClass = [];
// Always add base classes
animationClass.push('element');
// Add classes for active and inactive states
if (this.active) {
// Generate the class name
effectClass = `animation-in scale-easeInOutBounce`;
animationClass.push(effectClass);
} else {
// Generate the class name
effectClass = `animation-out scale-easeInOutBounce`;
animationClass.push(effectClass);
}
//requestAnimationFrame(() => { /* some fance function */ });
return animationClass;
},
triggerLabel(){
return !this.active ? 'Start Animation In' : 'Start Animation Out';
},
},
methods: {
trigger(){
this.active =!this.active
},
}
};
const app = createApp(App).mount('#app');
</script>
</body>
</html>
Solution
You need to trigger a "reflow" ( What is DOM reflow? )
In your classes() function you can do it like this:
requestAnimationFrame(() => {
const el = document.querySelector('.element')
el.style.animation = 'none';
el.offsetHeight; // Trigger reflow
el.style.animation = null;
});
Source: Restart animation in CSS3: any better way than removing the element?
Answered By - antja0
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.