In a previous article, we covered Vue transitions and animations and how to create effects using transition classes with nothing more than CSS and the transition
tag. Interestingly, you can do so much more with JavaScript by using it alone or combining it with CSS.
The transition
tag ships with something called event hooks, which allow JavaScript to affect transitions. The event hooks affect the element just like the transition classes in CSS. With that, you can run JavaScript code at every stage of attachment or removal of the HTML element from the DOM as the animation or transition is taking place.
These hooks enable you to run JS code before the animation starts, while it’s in progress, and immediately after it’s done. This extra functionality can give you more control or flexibility with your UI, promote interaction, and improve the user experience.
The transition
tag has default event hooks for JavaScript that attach themselves to methods, which have the actual code.
<transition @before-enter="beforeEnter" @enter="enter" @after-enter="afterEnter" @enter-cancelled="enterCancelled" @before-leave="beforeLeave" @leave="leave" @after-leave="afterLeave" @leave-cancelled="leaveCancelled" > [...] </transition>
@before-enter
allows JavaScript code to run for one frame before it’s attached to the DOM@enter
emits the code that runs as it attaches to the DOMafter-enter
emits the code that runs after it has been attached to the DOM@enter-cancelled
emits the code that clears the animation and aborts its playback (you can have other type of code there too)@before-leave
allows JavaScript code to run for one frame before it’s removed from the DOM@leave
emits the code that runs as it’s removed from the DOM@after-leave
emits the code that runs after it has been removed from the DOM@leave-cancelled
emits the code that runs if the animation is canceledLet’s look at an example.
<template> <div> <div class="container"> <button @click="display = !display">Switch</button> <transition @before-enter="beforeEnter" @enter="enter" @after-enter="afterEnter" @enter-cancelled="enterCancelled" @before-leave="beforeLeave" @leave="leave" @after-leave="afterLeave" @leave-cancelled="leaveCancelled"> <div class="item" v-if="display">1</div> </transition> </div> </div> </template> <style scoped> body { align-content: center; } .container { display: grid; grid-gap: 20px; width: 500px; margin: 0 auto; } .item { background-color: blue; height: 100px; } .fadeInClass { animation : fadeIn 1s; } .fadeOutClass { animation : fadeOut 1s; } @keyframes fadeIn { 0% { opacity : 0 } 100% { opacity : 1; } } @keyframes fadeOut { 0% { opacity : 1; } 100% { opacity : 0; } } </style> <script> export default { data () { return { display : false } }, methods : { beforeEnter () { console.log("about to") }, enter (el, done) { el.classList.add('fadeInClass'); console.log("enter") done(); }, afterEnter (el) { el.addEventListener('animationend', () =>{el.classList.remove('fadeInClass'); } ) console.log("after enter") }, enterCancelled () { console.log("enter cancelled") }, beforeLeave () { console.log("beforeLeave") }, leave (el, done) { el.classList.add('fadeOutClass') console.log("leave") done(); }, afterLeave () { console.log("after-leave"); }, leaveCancelled () { console.log("leave cancelled") } } } </script>
The example above offers a use case of how to combine event hooks in JavaScript and CSS to create animations. In this case, we used @keyframes
in CSS to create styles for both attaching and removing from the DOM. We then created the methods for our event hooks, where we added comments to the console and the styles to the element at each stage of attachment/removal with JavaScript.
Note: We added done()
to only enter
and leave
because it helps the element in Vue to know when the transition/animation is done in JavaScript, because it’s not timed like it is with CSS.
Interestingly, you can also use any of the event hooks in isolation to run JavaScript code, so you don’t necessarily need to attach all the hooks to the transition tag for it to work. You can use only what you need.
For instance, you can simply add @after-leave
to a transiton tag that’s already using CSS with the transition classes, and it’ll run whatever code you want after the animation has been removed from the DOM.
Here’s an example:
<template> <div> <div class="container"> <button @click="display = !display">Switch</button> <transition @after-leave="afterLeave" name="block"> <div class="item" v-if="display" >1</div> </transition> <div id="comment"></div> </div> </div> </template> <style scoped> body { align-content: center; } .container { display: grid; grid-gap: 20px; width: 500px; margin: 0 auto; } .item { background-color: blue; height: 100px; } .block-enter { } .block-enter-active { animation : fadeIn 1s; } .block-leave { } .block-leave-active { animation : fadeOut 1s } @keyframes fadeIn { 0% { opacity : 0 } 100% { opacity : 1; } } @keyframes fadeOut { 0% { opacity : 1; } 100% { opacity : 0; } } </style> <script> export default { data () { return { display : false } }, methods : { afterLeave () { document.getElementById('comment').innerHTML = `The random number is ${(Math.random())}` } } } </script>
@after-leave
is attached to the transition tag, which is already using transition classes for its operation. The @after-leave
hook takes effect after the element has been removed from the DOM. It then runs the afterLeave()
function and displays the statement about the random number. This can be reproduced with all the other event hooks we discussed about earlier.
If you’re using JavaScript hooks without any CSS at all, you can add :css="false"
to your trasition tag. This tells the transition tag not to listen to any CSS because, which it typically does by default.
<transition @before-enter="beforeEnter" @enter="enter" @after-enter="afterEnter" @enter-cancelled="enterCancelled" @before-leave="beforeLeave" @leave="leave" @after-leave="afterLeave" @leave-cancelled="leaveCancelled" :css="false"> <div class="item" v-if="display">1</div> </transition>
With JavaScript, you can control elements completely through the DOM, depending on what you want to achieve within your project. You can always fit JavaScript at any point in your animations with the transition hooks, giving you the flexibility to precisely manipulate elements and create better and more scalable applications for your users.
To learn more, check out this crash course.
Debugging Vue.js applications can be difficult, especially when there are dozens, if not hundreds of mutations during a user session. If you’re interested in monitoring and tracking Vue mutations for all of your users in production, try LogRocket.
LogRocket is like a DVR for web and mobile apps, recording literally everything that happens in your Vue apps, including network requests, JavaScript errors, performance problems, and much more. Instead of guessing why problems happen, you can aggregate and report on what state your application was in when an issue occurred.
The LogRocket Vuex plugin logs Vuex mutations to the LogRocket console, giving you context around what led to an error and what state the application was in when an issue occurred.
Modernize how you debug your Vue apps — start monitoring for free.
Hey there, want to help make our blog better?
Join LogRocket’s Content Advisory Board. You’ll help inform the type of content we create and get access to exclusive meetups, social accreditation, and swag.
Sign up nowBuild scalable admin dashboards with Filament and Laravel using Form Builder, Notifications, and Actions for clean, interactive panels.
Break down the parts of a URL and explore APIs for working with them in JavaScript, parsing them, building query strings, checking their validity, etc.
In this guide, explore lazy loading and error loading as two techniques for fetching data in React apps.
Deno is a popular JavaScript runtime, and it recently launched version 2.0 with several new features, bug fixes, and improvements […]