Vue.js Transitions & Animations
In this chapter, we will primarily discuss Vue.js transition effects and animation effects.
Transitions
Vue provides multiple ways to apply transition effects when inserting, updating, or removing DOM elements.
Vue offers a built-in transition wrapper component, which is used to wrap the component that needs to implement transition effects.
Syntax Format
<transition name = "nameoftransition">
<div></div>
</transition>
We can understand how Vue transitions work through the following example:
Example
<div id = "databinding">
<button v-on:click = "show = !show">Click Me</button>
<transition name = "fade">
<p v-show = "show" v-bind:style = "styleobj">Animation Example</p>
</transition>
</div>
<script type = "text/javascript">
var vm = new Vue({
el: '#databinding',
data: {
show:true,
styleobj :{
fontSize:'30px',
color:'red'
}
},
methods : {
}
});
</script>
In this example, clicking the "Click Me" button toggles the value of the variable show from true to false. If it is true, the content of the child element p tag is displayed.
The following code shows the transition tag wrapping the p tag:
<transition name = "fade">
<p v-show = "show" v-bind:style = "styleobj">Animation Example</p>
</transition>
A transition is essentially a fade-in and fade-out effect. Vue provides 6 classes to toggle during the transition of an element's display and hide:
v-enter: Defines the starting state of the entering transition. It takes effect before the element is inserted and is removed in the next frame after the element is inserted.v-enter-active: Defines the active state of the entering transition. It applies throughout the entire entering transition phase, takes effect before the element is inserted, and is removed after the transition/animation completes. This class can be used to define the duration, delay, and easing function of the entering transition.v-enter-to: (Version 2.1.8+) Defines the ending state of the entering transition. It takes effect in the next frame after the element is inserted (at the same timev-enteris removed) and is removed after the transition/animation completes.v-leave: Defines the starting state of the leaving transition. It takes effect immediately when the leaving transition is triggered and is removed in the next frame.v-leave-active: Defines the active state of the leaving transition. It applies throughout the entire leaving transition phase, takes effect immediately when the leaving transition is triggered, and is removed after the transition/animation completes. This class can be used to define the duration, delay, and easing function of the leaving transition.v-leave-to: (Version 2.1.8+) Defines the ending state of the leaving transition. It takes effect in the next frame after the leaving transition is triggered (at the same timev-leaveis removed) and is removed after the transition/animation completes.
For these class names that toggle during the transition, if you use a <transition> without a name, v- is the default prefix for these class names. If you use <transition name="my-transition">, then v-enter will be replaced with my-transition-enter.
v-enter-active and v-leave-active can control the different easing curves for the entering/leaving transitions, as shown in the example in the following section.
CSS Transitions
Usually, we use CSS transitions to achieve effects.
Example:
<div id = "databinding">
<button v-on:click = "show = !show">Click Me</button>
<transition name="slide-fade">
<p v-if="show">hello</p>
</transition>
</div>
<script type = "text/javascript">
new Vue({
el: '#databinding',
data: {
show: true
}
})
</script>
CSS Animations
CSS animations are used similarly to CSS transitions, but in animations, the v-enter class name is not immediately removed after the node is inserted into the DOM, but is removed when the animationend event is triggered.
Example:
<div id = "databinding">
<button v-on:click = "show = !show">Click Me</button>
<transition name="bounce">
<p v-if="show"> -- Learning is not just about technology, but also about dreams!!!</p>
</transition>
</div>
<script type = "text/javascript">
new Vue({
el: '#databinding',
data: {
show: true
}
})
</script>
Custom Transition Class Names
We can customize transition class names using the following attributes:
enter-classenter-active-classenter-to-class(2.1.8+)leave-classleave-active-classleave-to-class(2.1.8+)
Custom transition class names have higher priority than regular class names, allowing for better integration with third-party animation libraries like animate.css.
Example:
<div id = "databinding">
<button v-on:click = "show = !show">Click Me</button>
<transition
name="custom-classes-transition"
enter-active-class="animated tada"
leave-active-class="animated bounceOutRight"
>
<p v-if="show"> -- Learning is not just about technology, but also about dreams!!!</p>
</transition>
</div>
<script type = "text/javascript">
new Vue({
el: '#databinding',
data: {
show: true
}
})
</script>
Using Both Transitions and Animations
Vue must set up corresponding event listeners to know when a transition is complete. It can be transitionend or animationend, depending on the CSS rules applied to the element. If you use either one, Vue can automatically detect the type and set up the listener.
However, in some scenarios, you need to set both transition and animation effects on the same element. For example, the animation might be triggered and completed quickly, while the transition effect hasn't ended yet. In this case, you need to use the type attribute and set it to animation or transition to explicitly declare which type Vue should listen for.
Explicit Transition Duration
In many cases, Vue can automatically determine when the transition effect is complete. By default, Vue waits for the first transitionend or animationend event on the root element of the transition effect. However, this can be overriddenβfor example, we might have a carefully orchestrated series of transitions where some nested internal elements have delayed or longer transitions compared to the root element of the transition effect.
In such cases, you can customize an explicit transition duration (in milliseconds) using the duration attribute on the <transition> component:
<transition :duration="1000">...</transition>
You can also customize the entering and leaving durations separately:
<transition :duration="{ enter: 500, leave: 800 }">...</transition>
JavaScript Hooks
You can declare JavaScript hooks in the attributes:
HTML code:
<transition
v-on:before-enter="beforeEnter"
v-on:enter="enter"
v-on:after-enter="afterEnter"
v-on:enter-cancelled="enterCancelled"
v-on:before-leave="beforeLeave"
v-on:leave="leave"
v-on:after-leave="afterLeave"
v-on:leave-cancelled="leaveCancelled"
>
<!-- ... -->
</transition>
JavaScript code:
// ...
methods: {
// --------
// Entering
// --------
beforeEnter: function (el) {
// ...
},
// This callback is optional
// Used in conjunction with CSS
enter: function (el, done) {
// ...
done()
},
afterEnter: function (el) {
// ...
},
enterCancelled: function (el) {
// ...
},
// --------
// Leaving
// --------
beforeLeave: function (el) {
// ...
},
// This callback is optional
// Used in conjunction with CSS
leave: function (el, done) {
// ...
done()
},
afterLeave: function (el) {
// ...
},
// leaveCancelled only used with v-show
leaveCancelled: function (el) {
// ...
}
}
These hook functions can be used in conjunction with CSS transitions/animations or independently.
When using only JavaScript transitions, you must use done as a callback in enter and leave. Otherwise, they will be called synchronously, and the transition will complete immediately.
It is recommended to add v-bind:css="false" for elements that use only JavaScript transitions. This tells Vue to skip CSS detection and also avoids the influence of CSS during the transition.
A simple example using Velocity.js:
<div id = "databinding">
<button v-on:click = "show = !show">Click Me</button>
<transition
v-on:before-enter="beforeEnter"
v-on:enter="enter"
v-on:leave="leave"
v-bind:css="false"
>
<p v-if="show"> -- Learning is not just about technology, but also about dreams!!!</p>
</transition>
</div>
<script type = "text/javascript">
new Vue({
el: '#databinding',
data: {
show: false
},
methods: {
beforeEnter: function (el) {
el.style.opacity = 0
el.style.transformOrigin = 'left'
},
enter: function (el, done) {
Velocity(el, { opacity: 1, fontSize: '1.4em' }, { duration: 300 })
Velocity(el, { fontSize: '1em' }, { complete: done })
},
leave: function (el, done) {
Velocity(el, { translateX: '15px', rotateZ: '50deg' }, { duration: 600 })
Velocity(el, { rotateZ: '100deg' }, { loop: 2 })
Velocity(el, {
rotateZ: '45deg',
translateY: '30px',
translateX: '30px',
opacity: 0
}, { complete: done })
}
}
})
</script>
Initial Render Transition
You can set the transition for the initial render of a node using the appear attribute:
<transition appear>
<!-- ... -->
</transition>
By default, this is the same as the entering/leaving transition, and you can also customize the CSS class names.
<transition
appear
appear-class="custom-appear-class"
appear-to-class="custom-appear-to-class" (2.1.8+)
appear-active-class="custom-appear-active-class"
>
<!-- ... -->
</transition>
Custom JavaScript hooks:
<transition
appear
v-on:before-appear="customBeforeAppearHook"
v-on:appear="customAppearHook"
v-on:after-appear="customAfterAppearHook"
v-on:appear-cancelled="customAppearCancelledHook"
>
<!-- ... -->
</transition>
Transitions for Multiple Elements
We can set transitions for multiple elements, typically for lists and descriptions:
Note that when switching between elements with the same tag name, you need to set a unique value via the key attribute to mark them so that Vue can distinguish them. Otherwise, for efficiency, Vue will only replace the content inside the same tag.
<transition>
<table v-if="items.length > 0">
<!-- ... -->
</table>
<p v-else>Sorry, no content found.</p>
</transition>
Example:
<transition>
<button v-if="isEditing" key="save">
Save
</button>
<button v-else key="edit">
Edit
</button>
</transition>
In some scenarios, you can also use different states for the key attribute of the same element instead of v-if and v-else. The above example can be rewritten as:
<transition>
<button v-bind:key="isEditing">
{{ isEditing ? 'Save' : 'Edit' }}
</button>
</transition>
Transitions for multiple elements using multiple v-if can be rewritten as a single element transition with dynamic attributes. For example:
<transition>
<button v-if="docState === 'saved'" key="saved">
Edit
</button>
<button v-if="docState === 'edited'" key="edited">
Save
</button>
<button v-if="docState === 'editing'" key="editing">
Cancel
</button>
</transition>
Can be rewritten as:
<transition>
<button v-bind:key="docState">
{{ buttonMessage }}
</button>
</transition>
// ...
computed: {
buttonMessage: function () {
switch (this.docState) {
case 'saved': return 'Edit'
case 'edited': return 'Save'
case 'editing': return 'Cancel'
}
}
}
YouTip