单元素/组件的过渡

Vue 提供了 transition 的封装组件,在下列情形中,可以给任何元素和组件添加进入/离开过渡

  • 条件渲染 (使用 v-if)
  • 条件展示 (使用 v-show)
  • 动态组件
  • 组件根节点 这里是一个典型的例子:
  1. <div id="demo">
  2. <button v-on:click="show = !show">
  3. Toggle
  4. </button>
  5. <transition name="fade">
  6. <p v-if="show">hello</p>
  7. </transition>
  8. </div>
  1. new Vue({
  2. el: '#demo',
  3. data: {
  4. show: true
  5. }
  6. })
  1. .fade-enter-active, .fade-leave-active {
  2. transition: opacity .5s;
  3. }
  4. .fade-enter, .fade-leave-to /* .fade-leave-active below version 2.1.8 */ {
  5. opacity: 0;
  6. }

单元素/组件的过渡 - 图1

当插入或删除包含在 transition 组件中的元素时,Vue 将会做以下处理:

  • 自动嗅探目标元素是否应用了 CSS 过渡或动画,如果是,在恰当的时机添加/删除 CSS 类名。

  • 如果过渡组件提供了 JavaScript 钩子函数,这些钩子函数将在恰当的时机被调用。

  • 如果没有找到 JavaScript 钩子并且也没有检测到 CSS 过渡/动画,DOM 操作 (插入/删除) 在下一帧中立即执行。(注意:此指浏览器逐帧动画机制,和 Vue 的 nextTick 概念不同)

过渡的类名

在进入/离开的过渡中,会有 6 个 class 切换。

  • v-enter:定义进入过渡的开始状态。在元素被插入之前生效,在元素被插入之后的下一帧移除。

  • v-enter-active:定义进入过渡生效时的状态。在整个进入过渡的阶段中应用,在元素被插入之前生效,在过渡/动画完成之后移除。这个类可以被用来定义进入过渡的过程时间,延迟和曲线函数。

  • v-enter-to: 2.1.8版及以上 定义进入过渡的结束状态。在元素被插入之后下一帧生效 (与此同时 v-enter 被移除),在过渡/动画完成之后移除。

  • v-leave: 定义离开过渡的开始状态。在离开过渡被触发时立刻生效,下一帧被移除。

  • v-leave-active:定义离开过渡生效时的状态。在整个离开过渡的阶段中应用,在离开过渡被触发时立刻生效,在过渡/动画完成之后移除。这个类可以被用来定义离开过渡的过程时间,延迟和曲线函数。

  • v-leave-to: 2.1.8版及以上 定义离开过渡的结束状态。在离开过渡被触发之后下一帧生效 (与此同时 v-leave 被删除),在过渡/动画完成之后移除。

Transition Diagram

对于这些在过渡中切换的类名来说,如果你使用一个没有名字的 <transition>,则 v- 是这些类名的默认前缀。如果你使用了 <transition name="my-transition">,那么 v-enter 会替换为 my-transition-enter

v-enter-activev-leave-active 可以控制进入/离开过渡的不同的缓和曲线,在下面章节会有个示例说明。

CSS 过渡

常用的过渡都是使用 CSS 过渡。

下面是一个简单例子:

  1. <div id="example-1">
  2. <button @click="show = !show">
  3. Toggle render
  4. </button>
  5. <transition name="slide-fade">
  6. <p v-if="show">hello</p>
  7. </transition>
  8. </div>
  1. new Vue({
  2. el: '#example-1',
  3. data: {
  4. show: true
  5. }
  6. })
  1. /* 可以设置不同的进入和离开动画 */
  2. /* 设置持续时间和动画函数 */
  3. .slide-fade-enter-active {
  4. transition: all .3s ease;
  5. }
  6. .slide-fade-leave-active {
  7. transition: all .8s cubic-bezier(1.0, 0.5, 0.8, 1.0);
  8. }
  9. .slide-fade-enter, .slide-fade-leave-to
  10. /* .slide-fade-leave-active for below version 2.1.8 */ {
  11. transform: translateX(10px);
  12. opacity: 0;
  13. }

单元素/组件的过渡 - 图3

CSS 动画

CSS 动画用法同 CSS 过渡,区别是在动画中 v-enter 类名在节点插入 DOM 后不会立即删除,而是在 animationend 事件触发时删除。

示例:(省略了兼容性前缀)

  1. <div id="example-2">
  2. <button @click="show = !show">Toggle show</button>
  3. <transition name="bounce">
  4. <p v-if="show">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris facilisis enim libero, at lacinia diam fermentum id. Pellentesque habitant morbi tristique senectus et netus.</p>
  5. </transition>
  6. </div>
  1. new Vue({
  2. el: '#example-2',
  3. data: {
  4. show: true
  5. }
  6. })
  1. .bounce-enter-active {
  2. animation: bounce-in .5s;
  3. }
  4. .bounce-leave-active {
  5. animation: bounce-in .5s reverse;
  6. }
  7. @keyframes bounce-in {
  8. 0% {
  9. transform: scale(0);
  10. }
  11. 50% {
  12. transform: scale(1.5);
  13. }
  14. 100% {
  15. transform: scale(1);
  16. }
  17. }

单元素/组件的过渡 - 图4

自定义过渡的类名

我们可以通过以下特性来自定义过渡类名:

  • enter-class
  • enter-active-class
  • enter-to-class (2.1.8+)
  • leave-class
  • leave-active-class
  • leave-to-class (2.1.8+) 他们的优先级高于普通的类名,这对于 Vue 的过渡系统和其他第三方 CSS 动画库,如 Animate.css 结合使用十分有用。

示例:

  1. <link href="https://cdn.jsdelivr.net/npm/animate.css@3.5.1" rel="stylesheet" type="text/css">
  2. <div id="example-3">
  3. <button @click="show = !show">
  4. Toggle render
  5. </button>
  6. <transition
  7. name="custom-classes-transition"
  8. enter-active-class="animated tada"
  9. leave-active-class="animated bounceOutRight"
  10. >
  11. <p v-if="show">hello</p>
  12. </transition>
  13. </div>
  1. new Vue({
  2. el: '#example-3',
  3. data: {
  4. show: true
  5. }
  6. })

单元素/组件的过渡 - 图5

同时使用过渡和动画

Vue 为了知道过渡的完成,必须设置相应的事件监听器。它可以是 transitionendanimationend ,这取决于给元素应用的 CSS 规则。如果你使用其中任何一种,Vue 能自动识别类型并设置监听。

但是,在一些场景中,你需要给同一个元素同时设置两种过渡动效,比如 animation 很快的被触发并完成了,而 transition 效果还没结束。在这种情况中,你就需要使用 type 特性并设置 animationtransition 来明确声明你需要 Vue 监听的类型。

显性的过渡持续时间

2.2.0 新增

在很多情况下,Vue 可以自动得出过渡效果的完成时机。默认情况下,Vue 会等待其在过渡效果的根元素的第一个 transitionendanimationend 事件。然而也可以不这样设定——比如,我们可以拥有一个精心编排的一系列过渡效果,其中一些嵌套的内部元素相比于过渡效果的根元素有延迟的或更长的过渡效果。

在这种情况下你可以用 <transition> 组件上的 duration 属性定制一个显性的过渡持续时间 (以毫秒计):

  1. <transition :duration="1000">...</transition>

你也可以定制进入和移出的持续时间:

  1. <transition :duration="{ enter: 500, leave: 800 }">...</transition>

JavaScript 钩子

可以在属性中声明 JavaScript 钩子

  1. <transition
  2. v-on:before-enter="beforeEnter"
  3. v-on:enter="enter"
  4. v-on:after-enter="afterEnter"
  5. v-on:enter-cancelled="enterCancelled"
  6. v-on:before-leave="beforeLeave"
  7. v-on:leave="leave"
  8. v-on:after-leave="afterLeave"
  9. v-on:leave-cancelled="leaveCancelled"
  10. >
  11. <!-- ... -->
  12. </transition>
  1. // ...
  2. methods: {
  3. // --------
  4. // 进入中
  5. // --------
  6. beforeEnter: function (el) {
  7. // ...
  8. },
  9. // 当与 CSS 结合使用时
  10. // 回调函数 done 是可选的
  11. enter: function (el, done) {
  12. // ...
  13. done()
  14. },
  15. afterEnter: function (el) {
  16. // ...
  17. },
  18. enterCancelled: function (el) {
  19. // ...
  20. },
  21. // --------
  22. // 离开时
  23. // --------
  24. beforeLeave: function (el) {
  25. // ...
  26. },
  27. // 当与 CSS 结合使用时
  28. // 回调函数 done 是可选的
  29. leave: function (el, done) {
  30. // ...
  31. done()
  32. },
  33. afterLeave: function (el) {
  34. // ...
  35. },
  36. // leaveCancelled 只用于 v-show 中
  37. leaveCancelled: function (el) {
  38. // ...
  39. }
  40. }

这些钩子函数可以结合 CSS transitions/animations 使用,也可以单独使用。

当只用 JavaScript 过渡的时候,enterleave 中必须使用 done 进行回调。否则,它们将被同步调用,过渡会立即完成。

推荐对于仅使用 JavaScript 过渡的元素添加 v-bind:css="false",Vue 会跳过 CSS 的检测。这也可以避免过渡过程中 CSS 的影响。

一个使用 Velocity.js 的简单例子:

  1. <!--
  2. Velocity 和 jQuery.animate 的工作方式类似,也是用来实现 JavaScript 动画的一个很棒的选择
  3. -->
  4. <script src="https://cdnjs.cloudflare.com/ajax/libs/velocity/1.2.3/velocity.min.js"></script>
  5. <div id="example-4">
  6. <button @click="show = !show">
  7. Toggle
  8. </button>
  9. <transition
  10. v-on:before-enter="beforeEnter"
  11. v-on:enter="enter"
  12. v-on:leave="leave"
  13. v-bind:css="false"
  14. >
  15. <p v-if="show">
  16. Demo
  17. </p>
  18. </transition>
  19. </div>
  1. new Vue({
  2. el: '#example-4',
  3. data: {
  4. show: false
  5. },
  6. methods: {
  7. beforeEnter: function (el) {
  8. el.style.opacity = 0
  9. el.style.transformOrigin = 'left'
  10. },
  11. enter: function (el, done) {
  12. Velocity(el, { opacity: 1, fontSize: '1.4em' }, { duration: 300 })
  13. Velocity(el, { fontSize: '1em' }, { complete: done })
  14. },
  15. leave: function (el, done) {
  16. Velocity(el, { translateX: '15px', rotateZ: '50deg' }, { duration: 600 })
  17. Velocity(el, { rotateZ: '100deg' }, { loop: 2 })
  18. Velocity(el, {
  19. rotateZ: '45deg',
  20. translateY: '30px',
  21. translateX: '30px',
  22. opacity: 0
  23. }, { complete: done })
  24. }
  25. }
  26. })

单元素/组件的过渡 - 图6