Vue.js Transition

Vue.js provides a <transition> component which wraps the element or component you want to animate. It automatically adds three entering and three leaving CSS classes.

v-enter /v-leave and v-enter-to /v-leave-to define the starting and ending states of the transition.
v-enter-active /v-leave-active define the transition's configuration, such as duration, easing function, etc.

The <transition> component can have a name attribute. If we define one, it will replace the default v- prefix in all classes.
For example, if the name is set to "tab", the v-enter class will become tab-enter, and so on.

- Syntax:
<div id='demo'>
 <transition name='test'>
 <div>Content</div>
 </transition>
</div>

In the element added in <transition> we can use v-if and v-show for entering /leaving transitions. Then, in CSS style we apply properties for transition /animation to the CSS classes added by Vue.

- Here is a simple example with a button and a H4 tag to which we apply transition:
<style>
.cls_h {
color:#00e;
}
.test-enter-active, .test-leave-active {
 transition: opacity 1s;
}
.test-enter, .test-leave-to {
 opacity: 0;
}
</style>

<div id='demo'>
 <transition name='test'>
 <h3 v-show ='show' class='cls_h'>To have peace I transmit peace.</h3>
 </transition>
 <button v-on:click='show = !show'>Show /Hide</button>
</div>

<script>
var vm = new Vue({
 el: '#demo',
 data:{ show:false }
});
</script>
In the example above we apply css style for transition effect to the classes defined by Vue, but with the prefix "test" (the name of the <transition> tag): .test-enter-active, .test-leave-active, .test-enter, .test-leave-to.

Transition on Components

In the <transition> element we can add custom Vue components.
- In the following example it is defined a Vue component (here "comp_test") and included in <transition>:
<style>
.cls_h {
color:#00e;
}
.test-enter-active, .test-leave-active {
 transition: opacity 1s;
}
.test-enter, .test-leave-to {
 opacity: 0;
}
</style>

<div id='demo'>
 <transition name='test'>
 <comp_test v-show='show'></comp_test>
 </transition>
 <button v-on:click ='show = !show'>Show /Hide</button>
</div>

<script>
Vue.component('comp_test', {
 props: ['show'],
 data: function(){
 return {msg:'Giving and receiving are one; I give what I want to receive.'}
 },
 template: "<h3 class='cls_h'>{{msg}}</h3>"
});

var vm = new Vue({
 el: '#demo',
 data:{show:false}
});
</script>

Transition with v-if and v-else

You can also transition between raw elements using v-if and v-else.

- Example:
<style>
.fade-enter-active, .fade-leave-active {
 transition: opacity .5s;
}
.fade-enter, .fade-leave-to {
 opacity: 0;
}
</style>

<div id='demo'>
<transition name='fade'>
 <h3 v-if='rest ==1'>This is in the tag with v-if, rest ={{rest}}.</h3>
 <div v-else-if='rest ==2'>This is from v-else-if, rest ={{rest}}.</div>
 <h4 v-else>This content is from v-else, rest not 1 or 2; rest ={{rest}}.</h4>
</transition>
 Click to <button @click='altrElm'>Alternate elements</button>
</div>

<script>
var vm = new Vue({
 el: '#demo',
 data:{ rest:0, nr:0 },
 methods:{
 altrElm:function(){
 this.nr++;
 this.rest = this.nr %3;
 }
 }
});
</script>
When toggling between elements that have the same tag name, you must tell Vue that they are distinct elements by giving them unique key attributes. Otherwise, Vue's compiler will only replace the content of the element.
It's indicated to always add a key attribute when there are multiple items within a <transition> component.

- Example Syntax:
<transition>
 <button v-if='is_save' key='save'>Save</button>
 <button v-else key='edit'>Edit</button>
</transition>

Transition Modes

It's possible to transition between any number of elements, either by using multiple v-ifs or binding a single element to a dynamic property.
In the <transition> tag you can add a mode attribute to get different transition effect.
The mode attribute can have one of these two values: in-out and out-in.

- Test the example below and change "out-in" with "in-out" to see the difference.
<style>
.fade-enter-active, .fade-leave-active {
 transition: opacity .5s;
}
.fade-enter, .fade-leave-to {
 opacity: 0;
}
</style>

<div id='demo'>
Example with multiple <b>v-if</b>, without <b>mode</b> attribute: 
<transition name='fade'>
 <button @click='bState' v-if='b_state =="saved"' key='saved'>Save</button>
 <button @click='bState' v-if='b_state =="edited"' key='edited'>Edit</button>
</transition>
<br><br>

Example with a single element binded to a dynamic property (here is_save), and <b>mode</b> attribute: 
<transition name='fade' mode='out-in'>
 <button @click='btnState' v-bind:key='is_save'>{{ btn_txt }}</button>
</transition>
</div>

<script>
var vm = new Vue({
 el: '#demo',
 data:{ b_state:'saved', btn_txt:'Save', is_save:true},
 methods:{
 //for example with v-if
 bState: function(ev){
 this.b_state = (this.b_state =='saved') ? 'edited' :'saved';
 },

 //for example with single element binded to is_save
 btnState: function(ev){
 this.is_save = !this.is_save;
 this.btn_txt = this.is_save ? 'Save' :'Edit';
 }
 }
});
</script>

CSS Animation with Vue js

CSS animations are applied in the same way as CSS transitions, the difference being that v-enter is not removed after the element is inserted, but on an animationend event.

- Here is an example to see how animation works.
<style>
.cls_d {
background:#dadafe;
font-size:20px;
height:100px;
text-align:center;
width:180px;
}
@keyframes ex_anim {
 0% { background:#fe1234; width:0;height:0; font-size:0;}
 50% {
 border-radius: 100%;
 transform: rotate(180deg);
 }
 100% {
 background:#bbbbfe;
 transform: rotate(360deg);
 transform: scale(1.05);
 font-size:8px;
 }
}

.ro_x-enter-active {
 animation-name: ex_anim;
 animation-duration: 1.5s;
}
.ro_x-leave-active {
 animation: ex_anim reverse;
 animation-duration: 1.5s;
}
</style>

<div id='demo'>
 <transition name='ro_x'>
 <div v-show ='show' class='cls_d'>The past disappears, the moment remains.<br>Who am I?</div>
 </transition>
 <button v-on:click ='show = !show'>Show /Hide</button>
</div>

<script>
var vm = new Vue({
 el: '#demo',
 data:{ show:true }
});
</script>

Transition at the Initial Render

If you want to add animation at the start, you need to add the appear attribute in the transition tag.

- Here is the same animation example, but with the appear attribute. In this case we not need the v-show condition.
<style>
.cls_d {
background:#dadafe;
font-size:20px;
height:100px;
text-align:center;
width:180px;
}
@keyframes ex_anim {
 0% { background:#fe1234; width:0;height:0; font-size:0;}
 50% {
 border-radius: 100%;
 transform: rotate(180deg);
 }
 100% {
 background:#bbbbfe;
 transform: rotate(360deg);
 transform: scale(1.05);
 font-size:8px;
 }
}

.ro_x-enter-active {
 animation-name: ex_anim;
 animation-duration: 2s;
}
</style>

<div id='demo'>
 <transition name='ro_x' appear>
 <div class='cls_d'>The past disappears, the moment remains.<br>Who am I?</div>
 </transition>
</div>

<script>
var vm = new Vue({
 el: '#demo'
});
</script>

Custom Transition Classes

Vue.JS provides a list attributes that can be added to the <transition> element to can define custom classes for CSS transition.

These attributes will override the conventional class names.
Custom classes are useful when we want to use an external CSS library such as animate.css.

- Example, we use enter-active-class and leave-active-class attributes to set custom CSS classes for transition (classes used with animate.css: animated, tada, bounceOutRight):
<link href='//cdn.jsdelivr.net/npm/animate.css@3.5.1' rel='stylesheet' type='text/css'>

<div id='demo' style='text-align:center'>
<button @click='show = !show'>Toggle render</button>
<transition name='custom_cls' enter-active-class='animated tada' leave-active-class='animated bounceOutRight'>
 <h3 v-if='show'>Love Life</h3>
</transition>
</div>

<script>
var vm = new Vue({
 el: '#demo',
 data: { show: true }
});
</script>

Explicit Transition Duration

Vue waits for the transitionend and animationend event to detect if the animation or transition is done. Sometimes it can cause delay.
In such cases you can specify an explicit transition duration (in milliseconds) by binding the :duration property in the <transition> tag:
<transition :duration='1000'>...</transition>

Or with separate values for enter and leave durations:
<transition :duration='{ enter:500, leave:800 }'>...</transition>

Transition classes called as Methods

The transition classes can be called as methods using JavaScript Hooks attributes, defined with v-on: prefix and the name of the event to which the method is called.

- Syntax:
<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'
>
HTML Elements
</transition>

These hooks can be used in combination with CSS transitions /animations or on their own.

When using JavaScript-only transitions, a callback function is required for the enter and leave methods (see in the example below). Otherwise, the method will be called synchronously and the transition will finish immediately.

It's good to add v-bind:css='false' for JavaScript-only transitions so that Vue can skip the CSS detection. This also prevents CSS rules from interfering with the transition.

Example, using Vue and velocity.js. We perform animation with js methods on the <transition> element.
<div id='demo' style='text-align:center'>
<button @click='show = !show'>Toggle render</button>
<transition v-on:before-enter='beforeEnter' v-on:enter='enter' v-on:leave='leave' v-bind:css='false'>
 <h3 v-if='show'>Love Life</h3>
</transition>
</div>

<script>
document.write('<sc'+'ript src="//cdnjs.cloudflare.com/ajax/libs/velocity/1.2.3/velocity.min.js"></sc'+'ript>');

var vm = new Vue({
 el: '#demo',
 data: { show: false },
 methods: {
 beforeEnter: function(el){
 el.style.opacity = 0
 },
 //done callback is optional when used in combination with CSS
 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>

Daily Test with Code Example

HTML
CSS
JavaScript
PHP-MySQL
Which HTML5 tag defines marked text? (can be used to highlight parts of text)
<mark> <embed> <span>
<p>Free corses: <mark>coursesweb.net</mark> for Web Development.</p>
Which CSS pseudo-class adds a style to an element when the mouse is over it?
:focus :hover :active
a:hover {
  font-weight: bold;
  color: #00da01;
}
Click on the function which returns a string value that represents the number rounded to the x digits after the decimal point.
toPrecision(x) toFixed(x) floor(x)
var num = 12.34567;
num = num.toFixed(2);
alert(num);       // 12.35
Indicate the PHP function which reads an entire file into an array.
[) file() readfile()
$arr = file("a_file.txt", FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
var_export($arr);
Vue JS - Transition and Animation

Last accessed pages

  1. jQuery parent, children and nth-child() (11785)
  2. Add /Delete rows in HTML table with JavaScript (801)
  3. html2canvas - Save page screenshoot on server (1571)
  4. Get and Modify content of an Iframe (18271)
  5. PHP getElementById and getElementsByTagName (30454)

Popular pages this month

  1. Making DIV Contents Scroll Horizontally, with multiple Div`s inside (1269)
  2. Courses Web: PHP-MySQL JavaScript Node.js Ajax HTML CSS (1241)
  3. Tabs effect with CSS (1226)
  4. Contact page - CoursesWeb (1224)
  5. Insert, Select and Update NULL value in MySQL (729)