# Vue Animations & Transitions
use vue/js to start animation by adding an animation class, but css is doing the animation
<div class="block" :class="{ animate: animatedBlock }"></div>
css:
.block {
transition: transform 0.3s ease-in;
}
.animate {
transform: translateX(-150px);
}
or:
.animate {
animation: slide-fade 0.3s ease-out forwards;
}
@keyframes slide-fade {
0% {
transform: translateX(0) scale(1);
}
70% {
transform: translateX(-120px) scale(1.1);
}
100% {
transform: translateX(-150px) scale(1);
}
}
vue can delay the disappearance of an element until a animation has finished
# Use vue for animation
wrap content that gets shown/removed woth v-if or v-shoe in <transition>
can only contain 1 child
adds css utility classes to that element - vue applies the classes
mount:
v-enter-fromstart starev-enter-activev-enter-toend state
removal
- leave-from
- leave-active
- leave-to
-> makes it possible, to remove an element after the animation finished
css:
animation for adding:
.v-enter-from {
opacity: 0;
transform: translateY(30px);
}
.v-enter-active {
transition: all 0.3s ease-out;
}
.v-enter-to {
opacity: 1;
transform: translateY(0);
}
for removing:
.v-leave-from {
opacity: 1;
transform: translateY(0);
}
.v-leave-active {
transition: all 0.3s ease-in;
}
.v-leave-to {
opacity: 0;
transform: translateY(30px);
}
# Transition can also be used for animation:
.v-enter-active {
animation: slide-scale 0.3s ease-out;
}
.v-leave-active {
animation: slide-scale 0.3s ease-out;
}
@keyframes slide-scale {
0% {
transform: translateX(0) scale(1);
}
70% {
transform: translateX(-120px) scale(1.1);
}
100% {
transform: translateX(-150px) scale(1);
}
}
# Custom CSS class names
to use multiple transition-elemnts in one component:
instead of v- you can use a different prefix, like para-enter-active / para-leave-active. Use the name property:
<transition name="para">
<p v-if="paraIsVisible">only sometimes visible...</p>
</transition>
...
.para-enter-active {
animation: slide-scale 0.3s ease-out;
}
.para-leave-active {
/* transition: all 0.3s ease-in; */
animation: slide-scale 0.3s ease-out;
}
to change the whole-name:
<transition enter-to-class="some-class" enter-active-class="...">
<p v-if="paraIsVisible">only sometimes visible...</p>
</transition>
# Use tranistion on a component with mutliple root-elements
-> move the transition inside the component and use :open="condition" instead of v-if="condition"
-> use as aprop inside the component
you can use reverse to have the same animation backwards:
.modal-enter-active {
animation: modal 0.3s ease-out;
}
.modal-leave-active {
animation: modal 0.3s ease-out reverse;
}
# Transition between Mutliple Elements
if you toggle between two elements (only one will be on the dom), you can also have 2 elements inside the <transition>
use v-else
# mode
in-outfirst, the transition is run, then the other element is removedout-inremoval is animated first, and then the transition is run for the new element
css like this
.fade-button-enter-from,
.fade-button-leave-to {
opacity: 0;
}
.fade-button-enter-active {
transition: opacity 0.3s ease-out;
}
.fade-button-leave-active {
transition: opacity 0.3s ease-in;
}
.fade-button-enter-to,
.fade-button-leave-from {
opacity: 1;
}
# Transition Events
to run JS code, when animation starts or ends ect.
transition emits various events
@before-enterruns, when-enter-from-class i added@enter- like-enter-activecss class@after-enterafter the enter-animation is done@before-leave@leave@after-leave
you always get the element as an argument
methods: {
beforeEnter(el) {
console.log('before enter');
console.log(el);
},
beforeLeave(el) {
console.log('before leave');
console.log(el);
},
enter(el) {
console.log('enter');
console.log(el);
},
afterEnter(el) {
console.log('after enter');
console.log(el);
},
...
# Use JS instead of CSS for Transition
animation library
https://greensock.com/
enter has a second argument: -> the function to be called, when the function is done -> so afterEnter is emitted after enter is really done
enter(el, done)
fade-in
enter(el, done) {
console.log('enter');
console.log(el);
let round = 1;
const interval = setInterval(() => {
el.style.opacity = round * 0.01;
round++;
if (round > 100) {
clearInterval(interval);
done();
}
}, 20);
# Cancelled
@enter-cancelled
@leave-cancelled
better to store the interval in a data-property:
enter(el, done) {
console.log('enter');
console.log(el);
let round = 1;
this.enterInterval = setInterval(() => {
el.style.opacity = round * 0.01;
round++;
if (round > 100) {
clearInterval(this.enterInterval);
done();
}
}, 20);
},
so you can use this:
enterCancelled() {
clearInterval(this.enterInterval);
},
# Disable CSS Transitions
if you controll all of the animation with js, you can add: :css="false"
-> tell vue, that it will not use CSS for the transition -> vue skips the analysis, better performance
# Animated Lists
remove element fron an array:
removeUser(user) { this.users = this.users.filter(usr => usr !== user); },
to use multiple elements, use <transition-group>
<transition-group tag="ul" name="user-list">
<li v-for="user in users" :key="user" @click="removeUser(user)">
{{ user }}
</li>
</transition-group>
-> renders an element to the dom
tag defines, what element to render to the dom (any html-element or custom component)
name is the prefix for -enter-from... etc.
Vue adds class to transition-group to controll the other elements in the list
prefix-move
vue wil use transform for the animation of the other elements
# Animating Routes
in older version of vue, you can:
<transition name="route">
<router-view></router-view>
</transition>
css:
.route-enter-from {
}
.route-enter-active {
animation: slide-scale 1s ease-out;
}
.route-enter-to {
}
.route-leave-active {
animation: slide-scale 1s ease-in;
}
no longer works
# in vue3 - now:
access slotProps
<router-view v-slot="slotProps">
<transition name="route" mode="out-in">
<component :is="slotProps.Component"></component>
</transition>
</router-view>
the animation also runs on the first load, because vue starts with an empty router
to avoid that, you can use:
// main.js
router.isReady().then(() => {
app.mount('#app');
});
be aware:
<transition>needs exactly one child elementYour route components must NOT have multiple root elements!