Vue transition and animation

  vue.js

viaVue.jsThe transition system can be implemented in elements fromDOMAutomatically applies transition effects when inserting or removing.Vue.jsWill trigger for you at the right time.CSSTransition or animation, you can also provide the correspondingJavaScriptHook functions perform customDOMOperation.

In order to apply the transition effect, it needs to be used on the target element.transitionFeatures:

<div v-if="show" transition="my-transition"></div>

transitionFeatures can be used with the following resources:

  • v-if
  • v-show
  • V-for (triggered only when inserting and deleting, using vue-animated-list plug-in)
  • Dynamic component
  • On the component’s root node and triggered by Vue instance DOM methods such as vm.$appendTo(el).

When inserting or deleting elements with transitions, Vue will:

  1. Try to find JavaScript transition hook object with ID “my-transition “-register with Vue.transition(id, hooks) or transitions option. If found, the corresponding hook will be called in different stages of the transition.
  2. Automatically sniffs the target element for CSS transitions or animations, and adds/removes CSS class names when appropriate.
  3. If no JavaScript hook is found and no CSS transition/animation is detected, DOM operation (insert/delete) is executed immediately in the next frame.

CSS transition

Example

A typical CSS transition looks like this:

<div v-if="show" transition="expand">hello</div>

Then for.expand-transition,.expand-enterAnd.expand-leaveAdd CSS rules:

/* 必需 */
.expand-transition {
 transition: all .3s ease;
 height: 30px;
 padding: 10px;
 background-color: #eee;
 overflow: hidden;
}

/* .expand-enter 定义进入的开始状态 */
/* .expand-leave 定义离开的结束状态 */
.expand-enter, .expand-leave {
 height: 0;
 padding: 0 10px;
 opacity: 0;
}

You can achieve different transitions on the same element through dynamic binding:

<div v-if="show" :transition="transitionName">hello</div>

new Vue({
 el: '...',
 data: {
 show: false,
 transitionName: 'fade'
 }
})

In addition, it is possible to provideJavaScriptHook:

Vue.transition('expand', {

 beforeEnter: function (el) {
 el.textContent = 'beforeEnter'
 },
 enter: function (el) {
 el.textContent = 'enter'
 },
 afterEnter: function (el) {
 el.textContent = 'afterEnter'
 },
 enterCancelled: function (el) {
 // handle cancellation
 },

 beforeLeave: function (el) {
 el.textContent = 'beforeLeave'
 },
 leave: function (el) {
 el.textContent = 'leave'
 },
 afterLeave: function (el) {
 el.textContent = 'afterLeave'
 },
 leaveCancelled: function (el) {
 // handle cancellation
 }
})

Transitional CSS class name

The addition and switching of class names depends ontransitionThe value of the property. For example, transition=”fade “has three CSS class names:

  1. .fade-transitionAlways remain on the element.
  2. .fade-enterDefines the starting state for entering the transition. Only one frame is applied and then deleted immediately.
  3. .fade-leaveDefines the end state of the departure transition. Effective at the beginning of the departure transition and deleted at the end of it.

If the transition attribute has no value, the class name defaults to. v-transition, .v-enter, and. v-leave.

Custom transition class name

1.0.14 Add

We can declare the custom CSS transition class name in the transition JavaScript definition. These custom class names override the default class names. This is useful when you need to work with third-party CSS animation libraries, such as Animate.css:

<div v-show="ok" class="animated" transition="bounce">Watch me bounce</div>
Vue.transition('bounce', {
 enterClass: 'bounceInLeft',
 leaveClass: 'bounceOutRight'
})

Explicitly Declare CSS Transition Types

1.0.14 Add

Vue.js needs to add an event listener to the transition element to listen when the transition ends. Based on the CSS used, the event is either transitionend or animationend. If you use only one of the two, Vue.js will be able to automatically infer the corresponding event type according to the CSS rules in effect. However, in some cases an element may need to have both types of animation. For example, you may want Vue to trigger a CSS animation, while the element has CSS transition effect when the mouse is suspended. In this case, you need to explicitly declare the animation type (animation or transition) that you want Vue to handle:

Vue.transition('bounce', {
 // 该过渡效果将只侦听 `animationend` 事件
 type: 'animation'
})

Detailed explanation of transition process

When the show attribute changes, Vue.js will insert or delete < div > elements accordingly and change the transitional CSS class name according to the following rules:

  • If show becomes false, Vue.js will:
  1. Call the beforeLeave hook;
  2. Add the v-leave class name to the element to trigger the transition;
  3. Call leave hook;
  4. Wait for the transition to end (listen for the transitionend event);
  5. Remove elements from DOM and remove v-leave class name;
  6. Call the afterLeave hook.
  • If show becomes true, Vue.js will:
  1. Call beforeEnter hook;
  2. Add the v-enter class name to the element;
  3. Insert it into DOM;;
  4. Call the enter hook;
  5. Force CSS layout once so that v-enter does take effect. Then delete the v-enter class name to trigger the transition back to the original state of the element.
  6. Waiting for the transition to end;
  7. Call the afterEnter hook.

In addition, if the element is deleted while its entry transition is still in progress, theenterCancelledHook to clean up timers created by changes or enter. On the other hand, the same is true for the departure transition.

When all the hook functions above are called, their this points to the Vue instance to which they belong. Compilation Rule: The transition is compiled in the same context, and its this points to the same context.

Finally, enter and leave can have a second optional callback parameter to explicitly control how the transition ends. Therefore, there is no need to wait for the CSS transitionend event. Vue.js will wait for you to call this callback manually to end the transition. For example:

enter: function (el) {
 // 没有第二个参数
 // 由 CSS transitionend 事件决定过渡何时结束
}

vs.

enter: function (el, done) {
 // 有第二个参数
 // 过渡只有在调用 `done` 时结束
}

<p class="tip">When multiple elements are transitioned together, Vue.js will process them in batches and force the layout only once.

CSS animation

CSS animation usage is the same as CSS transition, except that the v-enter class name will not be deleted immediately after the node is inserted into DOM in the animation, but in theanimationendDelete when event triggers.

Example: (Compatibility Prefix Omitted)

<span v-show="show" transition="bounce">Look at me!</span>

.bounce-transition {
 display: inline-block; /* 否则 scale 动画不起作用 */
}
.bounce-enter {
 animation: bounce-in .5s;
}
.bounce-leave {
 animation: bounce-out .5s;
}
@keyframes bounce-in {
 0% {
 transform: scale(0);
 }
 50% {
 transform: scale(1.5);
 }
 100% {
 transform: scale(1);
 }
}
@keyframes bounce-out {
 0% {
 transform: scale(1);
 }
 50% {
 transform: scale(1.5);
 }
 100% {
 transform: scale(0);
 }
}

JavaScript transition

You can also use only JavaScript hooks without defining any CSS rules. When only JavaScript is used for transition, the enter and leave hooks need to call the done callback, otherwise they will be called synchronously and the transition will end immediately.

It is a good idea to explicitly declare css: false for JavaScript transition, Vue.js will skip CSS detection. This will also prevent inadvertently letting CSS rules interfere with the transition.

In the following example, we use jQuery to register a custom JavaScript transition:

Vue.transition('fade', {
 css: false,
 enter: function (el, done) {
 // 元素已被插入 DOM
 // 在动画结束后调用 done
 $(el)
 .css('opacity', 0)
 .animate({ opacity: 1 }, 1000, done)
 },
 enterCancelled: function (el) {
 $(el).stop()
 },
 leave: function (el, done) {
 // 与 enter 相同
 $(el).animate({ opacity: 0 }, 1000, done)
 },
 leaveCancelled: function (el) {
 $(el).stop()
 }
})

Then use the transition feature:

<p transition="fade"></p>

Asymptotic transition

Transition when used with v-for creates an asymptotic transition. Add a property stagger, enter-stagger, or leave-stagger to the transition element:

<div v-for="item in list" transition="stagger" stagger="100"></div>

Alternatively, provide a hook stagger, enter-stagger or leave-stagger for better control:

Vue.transition('stagger', {
 stagger: function (index) {
 // 每个过渡项目增加 50ms 延时
 // 但是最大延时限制为 300ms
 return Math.min(300, index * 50)
 }
})