元素/组件过渡

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

条件渲染 (使用 v-if)。
条件展示 (使用 v-show)。
动态组件。
组件根节点。
语法格式如

  1. <transition name = "nameoftransition">
  2. <div></div>
  3. </transition>
  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>Document</title>
  6. <!--引入 vue-->
  7. <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> </head>
  8. <body>
  9. <div id="demo">
  10. <button v-on:click="show = !show">
  11. 点我
  12. </button>
  13. <transition name="fade">
  14. <p v-if="show">动画实例</p>
  15. </transition>
  16. </div>
  17. <script>
  18. new Vue({
  19. el: '#demo',
  20. data: {
  21. show: true
  22. }
  23. })
  24. </script>
  25. </body>
  26. </html>

实例中通过点击 “点我” 按钮将变量 show 的值从 true 变为 false。如果为 true 显示 子元素 p 标签的内容。

实例中通过点击 “点我” 按钮将变量 show 的值从 true 变为 false。如果为 true 显示 子元素 p 标签的内容。

  1. <transition name="fade">
  2. <p v-if="show">动画实例</p>
  3. </transition>

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

自动嗅探目标元素是否应用了 CSS 过渡或动画,如果是,在恰当的时机添加/删 除 CSS 类名。
如果过渡组件提供了 JavaScript 钩子函数,这些钩子函数将在恰当的时机被调用。
如果没有找到 JavaScript 钩子并且也没有检测到 CSS 过渡/动画,DOM 操作 (插 入/删除) 在下一帧中立即执行。(注意:此指浏览器逐帧动画机制,和 Vue 的 nextTick 概 念不同)。

过渡其实就是一个淡入淡出的效果。Vue在元素显示与隐藏的过渡中,提供了 6 个 class 来切换

004动画和过度 - 图1

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

CSS 过渡

常用的 Vue 过渡效果都是使用 CSS 过渡 transition。我们首先看一个简单的切换显示按 钮,

  1. <div id="app">
  2. <button @click="show=!show">点我</button>
  3. <div v-if="show">Hello world</div>
  4. </div>
  5. <script>
  6. new Vue({
  7. el: '#app',
  8. data: {
  9. show: true
  10. }
  11. })
  12. </script>

我们现在希望 Hello world 能有一个渐隐渐现的效果,那么就需要在 div 外层包裹一个 transition 标签

  1. <div id="app">
  2. <button @click="show=!show">点我</button>
  3. <transition name="fade">
  4. <div v-if="show">Hello world</div>
  5. </transition>
  6. </div>

当然只是这样也是无法形成过渡效果的。仍需在 transition 标签中添加 class 样式,只不过 class 样式不需要我们手动添加,Vue 在运行中会自动的构建一个动画的流程

004动画和过度 - 图2

当动画执行的一瞬间,会自动在 div 上增加两个 class 名字,分别是 fade-enter 和 fade-enter-active,因为 transiton 标签 name 是 fade。
当动画运行到第二帧时,Vue 又会把 fade-enter 删除,然后添加一个 fade-enter-to,再当动画执行到结束的一瞬间,又把 fade-enter-active 和 fade-enter-to 删除掉

  1. <head>
  2. <style>
  3. .fade-enter{
  4. opacity: 0;
  5. }
  6. .fade-enter-active{
  7. transition: opacity 3s;
  8. }
  9. </style>
  10. </head>
  11. <body>
  12. <div id="app">
  13. <button @click="show=!show">点我</button>
  14. <transition name="fade">
  15. <div v-if="show">Hello world</div>
  16. </transition>
  17. </div>
  18. <script>
  19. new Vue({
  20. el: '#app',
  21. data: {
  22. show: true
  23. }
  24. })
  25. </script>
  26. </body>

在上 图 Vue动画过渡图中,我们发现fade-enter-active是全程存在的,它的作用是,如果监听到了元素opacity发生了变化,那么就让这个变化在3s内完成。
再来看Vue元素从显示到隐藏的动画效果,代码如下:

  1. <style>
  2. .v-enter{
  3. opacity: 0;
  4. }
  5. .v-enter-active{
  6. transition: opacity 3s;
  7. }
  8. .v-leave-to{
  9. opacity: 0;
  10. }
  11. .v-leave-active{
  12. transition: opacity 3s;
  13. }
  14. </style>

CSS 动画

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

在元素 enter 和 leave 时都增加缩放 scale 效果

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>Document</title>
  6. <!--引入vue-->
  7. <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
  8. <style>
  9. .bounce-enter-active{
  10. animation:bounce-in .5s;
  11. }
  12. .bounce-leave-active{
  13. animation:bounce-in .5s reverse;
  14. }
  15. @keyframes bounce-in{
  16. 0%{transform:scale(0);}
  17. 50%{transform:scale(1.5);}
  18. 100%{transform:scale(1);}
  19. }
  20. </style>
  21. </head>
  22. <body>
  23. <div id="app">
  24. <button v-on:click="show = !show">点我</button>
  25. <transition name="bounce">
  26. <p v-if="show">Hello World</p>
  27. </transition>
  28. </div>
  29. <script>
  30. new Vue({
  31. el: '#app',
  32. data: {
  33. show: true
  34. }
  35. })
  36. </script>
  37. </body>
  38. </html>

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

在一些场景中,需要给同一个元素同时设置两种过渡动效。
css 过渡和动画同时使用

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>Document</title>
  6. <!--引入 vue-->
  7. <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
  8. <style>
  9. .fade-enter,.fade-leave-to{
  10. opacity:0;
  11. }
  12. .fade-enter-active,.fade-leave-active{
  13. transition:opacity 1s;
  14. animation:bounce-in 5s;
  15. }
  16. @keyframes bounce-in{
  17. 0%{transform:scale(0);}
  18. 50%{transform:scale(1.5);}
  19. 100%{transform:scale(1);}
  20. }
  21. </style>
  22. </head>
  23. <body>
  24. <div id="app">
  25. <button v-on:click="show = !show">点我</button>
  26. <transition name="fade" type="transition">
  27. <p v-if="show">Hello World</p>
  28. </transition>
  29. </div>
  30. <script>
  31. new Vue({
  32. el: '#app',
  33. data: {
  34. show: true,
  35. },
  36. })
  37. </script>
  38. </body>
  39. </html>

使用过渡类实现动画

自定义过渡的类名

通过以下特性来自定义过渡类名

enter-class
enter-active-class
leave-class
leave-active-class

  1. 他们的优先级高于普通的类名,这对于 Vue 的过渡系统和其他第三方 CSS 动画库, Animate.css 结合使用十分有用。
  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>Document</title>
  6. <!--引入 vue-->
  7. <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
  8. <style>
  9. .fade-in-active, .fade-out-active{
  10. transition: all 1.5s ease
  11. }
  12. .fade-in-enter, .fade-out-active{
  13. opacity: 0
  14. }
  15. </style>
  16. </head>
  17. <body>
  18. <div id="app">
  19. <button @click="show = !show">
  20. 点我
  21. </button>
  22. <transition name="fade"
  23. enter-class="fade-in-enter"
  24. enter-active-class="fade-in-active"
  25. leave-class="fade-out-enter"
  26. leave-active-class="fade-out-active">
  27. <p v-show="show">hello</p>
  28. </transition>
  29. </div>
  30. <script>
  31. new Vue({
  32. el: '#app',
  33. data: {
  34. show: true
  35. }
  36. })
  37. </script>
  38. </body>
  39. </html>

上面代码中,原来默认的 fade-enter 类对应 fade-in-enter,fade-enter-active 类对应 fade-in-active,依次类推

CSS过渡钩子函数

除了用CSS过渡的动画来实现Vue的组件过渡,还可以用JavaScript的钩子函数来实现,在钩子函数中直接操作DOM。可以在属性中声明 JavaScript 钩子,代码如下:

  1. <transition v-on:before-enter="beforeEnter" v-on:enter="enter"
  2. v-on:after-enter="afterEnter" v-on:enter-cancelled="enterCancelled"
  3. v-on:before-leave="beforeLeave" v-on:leave="leave"
  4. v-on:after-leave="afterLeave"
  5. v-on:leave-cancelled="leaveCancelled" > <!-- ... --> </transition>

Js 代码

  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 使用,也可以单独使用。

引入Velocity.js 来配合使用 JavaScript 过渡

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>Document</title>
  6. <!--引入 vue-->
  7. <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
  8. <!--
  9. Velocity 和 jQuery.animate 的工作方式类似,也是用来实现 JavaScript 动画的一个很棒 的选择-->
  10. <script
  11. src="https://cdnjs.cloudflare.com/ajax/libs/velocity/1.2.3/velocity.min.j s"></script>
  12. </head>
  13. <body> <div id="app">
  14. <button @click="show = !show">
  15. 点我
  16. </button>
  17. <transition
  18. v-on:before-enter="beforeEnter"
  19. v-on:enter="enter"
  20. v-on:leave="leave"
  21. v-bind:css="false">
  22. <p v-if="show">
  23. Hello
  24. </p>
  25. </transition>
  26. </div>
  27. <script>
  28. new Vue({
  29. el: '#app',
  30. data: {
  31. show: false
  32. },
  33. methods: {
  34. beforeEnter: function (el) {
  35. el.style.opacity = 0
  36. el.style.transformOrigin = 'left'
  37. },
  38. enter: function (el, done) {
  39. Velocity(el, { opacity: 1, fontSize: '1.4em' }, { duration:
  40. 300 })
  41. Velocity(el, { fontSize: '1em' }, { complete: done })
  42. },
  43. leave: function (el, done) {
  44. Velocity(el, { translateX: '15px', rotateZ: '50deg' },
  45. { duration: 600 })
  46. Velocity(el, { rotateZ: '100deg' }, { loop: 2 })
  47. Velocity(el, {
  48. rotateZ: '45deg',
  49. translateY: '30px',
  50. translateX: '30px',
  51. opacity: 0
  52. }, { complete: done })
  53. }
  54. }
  55. })
  56. </script>
  57. </body> </html>