Animating between routes with route transitions in Vue
Working on a Vue.js application, there’s a high chance that components or items are going to be inserted, updated from the DOM. It’s always good practice to ease that process to obtain a great user experience.
In this article, I’ll be giving a brief overview of the difference in making a Vue application smooth by applying Vue transitions to routes.
Here’s how Route transitions look in our app:
Applying animations to your routes
The type of animations you want to apply to routes my differ for each route or you use a global animation for all routes.
To animate components in Vue, we use the wrapper component; transition
.
So the root element in the component to be rendered will be wrapped with the transition
component if you want per-route transitions or wrapping router-view
in the base component with transition
if you want a global dynamic transition.
Aside from wrapping the templates in a transition
component, we also specify the name of the animation which we will use in CSS to create the animations.
Transition classes
There are six classes that represent the different states in an animation. They are the enter/leave
transition classes.
v-enter
v-enter-active
v-enter-to
v-leave
v-leave-active
v-leave-to
These six classes in that order are responsible for the flow of the animations, to learn more about what each of them is, check out the official doc.
You’ll notice the v-
prefix, we use that if the animation’s name was not specified for the transition
wrapper. It’s also possible to specify a custom class to apply for a certain transition state:
<transition enter-active-class="custom-class-here">
<h1>Hello there</h1>
</transition>
This way, we can use custom animation libraries like Animate.css etc.
Per-Route Vue Transitions
Take this single file component for example:
<template>
<transition name="fade">
<h3> Login </h3>
</transition>
</template>
<script>
export default {
name: 'login',
data(){
return {}
}
}
</script>
<style scoped>
/*transition the opacity when the element enters and leaves the DOM*/
.fade-enter-active, .fade-leave-active {
transition: opacity .5s;
}
/*set opacity to 0 at element's entrance and exit*/
.fade-enter, .fade-leave-to {
opacity: 0;
}
</style>
With this method, we can have different animations for separate routes.
Global dynamic Vue transitions
And if we wanted to have unified route transitions based on the route, we can do achieve this by watching the $route object. Determining the path being navigated to will help us bind the correct name to the transition
wrapper.
<template>
<nav>
<h2>Title</h2>
</nav>
<transition :name="animationName" >
<router-view class="child-view" />
</transition>
</template>
<script>
export default {
data(){
return{
animationName = undefined
}
}
watch: {
'$route'(to, from){
const to_depth = to.path.split('/').length
const to_depth = from.path.split('/').length
this.animationName = to_depth < from_depth ? 'slide-right' : 'slide-left'
}
}
}
</script>
<style scoped>
.fade-enter-active,
.fade-leave-active {
transition: opacity 0.5s ease;
}
.fade-enter,
.fade-leave-active {
opacity: 0;
}
.child-view {
position: absolute;
width: 100%;
left: 0;
transition: all 0.5s cubic-bezier(0.55, 0, 0.1, 1);
}
.slide-left-enter,
.slide-right-leave-active {
opacity: 0;
-webkit-transform: translate(30px, 0);
transform: translate(30px, 0);
}
.slide-left-leave-active,
.slide-right-enter {
opacity: 0;
-webkit-transform: translate(-30px, 0);
transform: translate(-30px, 0);
}
</style>
The elements to be rendered in router-view
had to be given am absolute position so they don’t appear to glitch during animations.
I built an app using this Global dynamic route method a while back, you can check it out here