第5章Vue过渡和动画
在Vue 
项目中使用过渡和动画能优化用户体验和页面的交互性、影响用户的行为、引
导用户的注意力以及帮助用户看到自己动作的反馈。例如,Vue 
导航切换使用了过渡动
画,用户体验更友好。本章将结合案例讲解Vue 
项目中过渡和动画的实现,及其在多个元
素或组件中的使用方法。


● 了解过渡和动画的含义
● 掌握内置过渡类名及自定义类名的使用方法
● 掌握单元素、多元素、多组件的过渡
● 掌握列表过渡的实现方法
你无法决定明天是晴是雨,也无法决定此刻的坚持能得到什么。但你能决定今天有
没有准备好雨伞,以及是否足够努力。胡思乱想少一点,脚踏实地多一些,就会距离成功
更近一步。


121 
5.1 过渡与动画
5.1.1 了解过渡与动画 
在CSS3中,过渡属性通过transition实现,动画属性通过animation实现。Vue也
实现了过渡与动画,在插入、更新或者移除DOM 时,Vue提供了多种过渡效果。Vue.js 
会在适当的时机触发CSS过渡或动画,也可以提供相应的JavaScript钩子函数以在过渡
过程中执行自定义的DOM 操作。
Vue提供了内置的过渡封装组件,即transition组件,其语法格式如下: 
1 <transition name="fade"> 
2 <!--需要添加过渡的div 标签--> 
3 <div></div> 
4 </transition> 
上述代码中,<transition>标签用来放置需要添加过渡的div元素,使用name属性
可以设置前缀,如果将name属性设置为fade,那么“fade-”就是在过渡中切换的类名前
缀,如fade-enter、fade-leave等。如果<transition>标签上没有设置name属性名,那么
“v-”就是这些类名的默认前缀,如v-enter、v-leave等。Vue提供了6个CSS类名,分别为
v-enter、v-enter-active、v-enter-to、v-leave、v-leave-active、v-leaveto。
通过<transition>标签搭配CSS动画(如@keyframes)可以实现动画效果,另外, 
<transition>标签还提供了一些钩子函数,可以结合JavaScript代码完成动画效果,具体
内容会在后文讲解。
5.1.2 transition 组件
Vue提供了transition的封装组件,在下列情形中,可以给任何元素和组件添加进入/ 
离开过渡: 
● 条件渲染(使用v-if) 
● 条件展示(使用v-show) 
● 动态组件
● 组件根节点
Vue为transition提供了3个进入过渡的类和3个离开过渡的类,具体如表5-1所示。
表5-1 过渡类型
过渡状态过渡类型说 明
进入(enter) 
v-enter 进入过渡的开始状态,作用于开始的一帧
v-enter-active 进入过渡生效时的状态,作用于整个过程
v-enter-to 进入过渡的结束状态,作用于结束的一帧

122 
续表
过渡状态过渡类型说 明
离开(leave) 
v-leave 离开过渡的开始状态,作用于开始的一帧
v-leave-active 离开过渡生效时的状态,作用于整个过程
v-leave-to 离开过渡的结束状态,作用于结束的一帧 
表5-1中,6个类的生效时间如下。
● v-enter:在元素被插入之前生效,在元素被插入之后的下一帧移除。
● v-enter-active:在整个进入过渡的阶段中应用,在元素被插入之前生效,在过渡动
画完成之后移除。
● v-enter-to:在元素被插入之后的下一帧生效(与此同时,v-enter被移除),在过渡
动画完成之后移除。
● v-leave:在离开过渡被触发时立刻生效,下一帧被移除。
● v-leave-active:在整个离开过渡的阶段中应用,在离开过渡被触发时立刻生效,在
过渡动画完成之后移除。
● v-leave-to:在离开过渡被触发之后的下一帧生效(与此同时,v-leave被移除),在
过渡动画完成之后移除。
Vue过渡具体如图5-1所示。
图5-1 Vue过渡
下面通过一个案例演示如何使用内置的class类名实现过渡。
【例5-1】 使用内置的class类名实现过渡。
(1)创建文件夹chapter05,在该目录下创建demo01.html文件,具体代码如下: 
1 <!DOCTYPE html> 
2 <html lang="zh"> 
3 <head> 
4 <meta charset="UTF-8"> 
5 <title>Transition 标签</title> 
6 <style> 
7 .box { 
8 width: 200px;

123 
9 height: 50px; 
10 background-color: orange; 
11 } 
12 /* 进入和离开的过程*/ 
13 .fade-enter-active, .fade-leave-active { 
14 transition: width 3s; /* width 的变化,动画时间是3 秒*/ 
15 } 
16 /* 进入的初始状态和离开的结束状态*/ 
17 .fade-enter, .fade-leave-to { 
18 width: 0px; 
19 } 
20 /* 进入的结束状态和离开的初始状态*/ 
21 .fade-enter-to, .fade-leave { 
22 width: 200px; 
23 } 
24 </style> 
25 </head> 
26 <body> 
27 <div id="app"> 
28 <button type="button" @click="show=!show">Toggle</button> 
29 <transition name="fade"> 
30 <div class="box" v-if="show"> 
31 <h1>Hello,Vue!</h1> 
32 </div> 
33 </transition> 
34 </div> 
35 <script src="vue.js"></script> 
36 <script> 
37 var vm = new Vue({ 
38 el: '#app', 
39 data: { 
40 show: true 
41 } 
42 }) 
43 </script> 
44 </body> 
45 </html> 
在上述代码中,第29行将<transition>标签的name属性值设置为fade,这里的
fade是自定义类名前缀,因此在写CSS样式时,相对应的类名前缀以“fade-”开头;如果
transition不设置name属性,则第12~23行设置的CSS类均以“v-”为前缀;第30行的
div元素为一个长方形,通过使用v-if指令切换组件的可见性,通过show 设置显示的状
态,这样在单击按钮时,可以通过切换布尔值实现元素的显示和隐藏。在代码的第12~23 
行编写以“fade-”开头的CSS样式,以实现动画效果。

124 
(2)在浏览器中打开demo01.html文件,运行结果如图5-2所示。
图5-2 运行初始效果
在图5-2所示的页面中,单击Toggle按钮,会看到图形宽度变化的动画效果,其变化
过程中的某个效果如图5-3所示。
图5-3 动画效果 
5.2 单元素/组件的过渡
实现过渡动画通常有三种方式,一是使用Vue的<transition>标签结合CSS样式实
现动画;二是利用animate.css结合transition实现动画;三是利用Vue中的钩子函数实现
动画。下面具体讲解实现过渡动画的三种方式。
5.2.1 使用@ keyframes 创建CSS 动画
使用@keyframes创建CSS动画时,v-enter类名在节点插入DOM 后不会立即删除, 
而是在animationend(动画结束)事件触发时删除。
@keyframes规则创建动画是指将一套CSS样式逐步演变成另一套样式,在创建动
画的过程中可以多次改变CSS样式,通过百分比或关键词from 和to(等价于0和100%) 
规定动画的状态。@keyframes的语法格式如下: 
1 @keyframes animation-name { 
2 keyframes-selector { css-styles; } 
3 } 
在上述语法中,keyframes-selector表示动画时长的百分比,css-styles表示一个或者
多个合法的CSS样式属性。
下面通过例5-2演示如何使用@keyframes创建CSS动画。
【例5-2】 使用@keyframes创建CSS动画。

125 
(1)创建chapter05/demo02.html文件,具体代码如下: 
1 <!DOCTYPE html> 
2 <html lang="zh"> 
3 <head> 
4 <meta charset="UTF-8"> 
5 <title>Transition 标签</title> 
6 <style> 
7 .box { 
8 width: 200px; 
9 height: 50px; 
10 background-color: orange; 
11 } 
12 .v-enter-active { 
13 animation: animate 1s; 
14 } 
15 .v-leave-active { 
16 animation: animate 1s reverse; 
17 } 
18 @keyframes animate { 
19 0%{ 
20 opacity: 0; 
21 transform: translateX(400px) scale(1); 
22 } 
23 50%{ 
24 opacity: .5; 
25 transform: translateX(200px) scale(1.5); 
26 } 
27 100%{ 
28 opacity: 1; 
29 transform: translateX(0) scale(1); 
30 } 
31 } 
32 </style> 
33 </head> 
34 <body> 
35 <div id="app"> 
36 <button @click="show = !show">click</button> 
37 <transition> 
38 <div class="box" v-if="show">hello world</div> 
39 </transition> 
40 </div> 
41 <script src="vue.js"></script> 
42 <script>

126 
43 var vm = new Vue({ 
44 el: '#app', 
45 data: { 
46 show: true 
47 } 
48 }) 
49 </script> 
50 </body> 
51 </html> 
在上述代码中,第36行给button按钮添加了单击事件,通过单击按钮可以改变变量
show的值,<transition>标签没有设置name属性,所以第12~17行的CSS样式使用了
“v-”作前缀。第18~31行用于通过@keyframes规则创建名称为animate的动画样式, 
其中,0表示动画的开始状态,100%表示动画的结束状态。
(2)在浏览器中打开demo02.html文件,如图5-4所示。
图5-4 页面初始效果
在图5-4所示的页面中,单击click按钮,会看到图形变化的动画效果,其变化过程中
的某个效果如图5-5所示。
图5-5 CSS动画
5.2.2 animate.css 结合transition 实现动画
animate.css是一个跨浏览器的CSS3动画库,它内置了很多经典的CSS3动画,使
用起来很方便。
animate.css的官网地址是https://daneden.github.io/animate.css/。
下面通过例5-3讲解如何使用自定义类名和animate.css库实现动画效果。
【例5-3】 使用自定义类名和animate.css库实现动画效果。
(1)创建chapter05/demo03.html文件,并且引入animate.css,具体代码如下: 
1 <!DOCTYPE html> 
2 <html lang="zh"> 
3 <head>

127 
4 <meta charset="UTF-8"> 
5 <title>animation.css</title> 
6 <link rel="stylesheet" 
href =" https://cdnjs. cloudflare. com/ajax/libs/animate. css/4. 1. 1/ 
animate.min.css"/> 
7 <style> 
8 .box { 
9 width: 200px; 
10 height: 50px; 
11 background-color: orange; 
12 } 
13 </style> 
14 </head> 
15 <body> 
16 <div id="app"> 
17 <button @click="show = !show">click</button> 
18 <transition 
19 enter-active-class="animated bounceInLeft" 
20 leave-active-class="animated bounceOutLeft" > 
21 <div class="box" v-if="show">hello world</div> 
22 </transition> 
23 </div> 
24 <script src="vue.js"></script> 
25 <script> 
26 var vm = new Vue({ 
27 el: '#app', 
28 data: { 
29 show: true 
30 } 
31 }) 
32 </script> 
33 </body> 
34 </html> 
上述代码中,第6行引入了animate.css文件,第19、20行给<transition>标签设置
了enter-active-class与leave-active-class两个属性,用来自定义类名,属性值为animate.css动
画库中定义好的类名。例如,第19行的animatedbounceInLeft包含两个类名,animated 
是基本的类名,任何想实现动画的元素都要添加它;bounceInLeft是动画的类名, 
bounceInLeft表示入场动画,bounceOutLeft表示出场动画。
(2)在浏览器中运行demo03.html文件,单击click按钮,即可看到文字显示或隐藏
的动画效果,如图5-6所示。

128 
图5-6 初始效果
5.2.3 钩子函数实现动画
除了使用CSS动画外,还可以借助JavaScript完成动画。<transition>标签中定义
了一些动画钩子函数,可以用来实现动画,包括如下: 
1 <transition> 
2 @before-enter="beforeEnter" 
3 @enter="enter" 
4 @after-enter="afterEnter" 
5 @enter-cancelled="enterCancelled" 
6 @before-leave="beforeLeave" 
7 @leave="leave" 
8 @after-leave="afterLeave" 
9 @leave-cancelled="leaveCancelled" 
10 v-bind:css="false"> 
11 </transition> 
在上述代码中,入场钩子函数分别是beforeEnter(入场前)、enter(入场)、afterEnter 
(入场后)和enterCancelled(取消入场),出场钩子函数分别是beforeLeave(出场前)、leave 
(出场)、afterLeave(场后)和leaveCancelled(取消出场);第10行为仅使用JavaScript过
渡的元素添加v-bind:css="false",表示Vue会跳过CSS的检测,以免在过渡过程中受到
CSS的影响。
下面通过例5-4讲解如何使用钩子函数实现动画效果。
【例5-4】 使用钩子函数实现动画效果。
(1)创建chapter05/demo04.html文件,具体代码如下: 
1 <!DOCTYPE html> 
2 <html lang="zh"> 
3 <head> 
4 <meta charset="UTF-8"> 
5 <title>动画中的JavaScript 钩子函数的实现</title> 
6 <script src="vue.js"></script> 
<style> 
.ball { 
7 width: 15px; 
8 height: 15px;

129 
9 border-radius: 50%; 
10 background-color: orangered; 
11 } 
12 </style> 
13 </head> 
14 <body> 
15 <div id="app" > 
16 <input type="button" value="快到碗里来" @click="flag=!flag"> 
17 <transition 
18 @before-enter="beforeEnter" 
19 @enter="enter" 
20 @after-enter="afterEnter"> 
21 <div class="ball" v-show="flag"></div> 
22 </transition> 
23 </div> 
24 <script> 
25 new Vue({ 
26 el: '#app', 
27 data: { 
28 flag: false 
29 }, 
30 methods: { 
31 //设置小球开始动画之前的起始位置
32 beforeEnter(el) { 
33 el.style.transform = "translate(0, 0)" 
34 }, 
35 enter(el, done) { 
36 //这句话没有实际的作用,但如果不写,出不来动画效果
37 //可以认为el.offsetWidth 会强制动画刷新
38 el.offsetWidth 
39 el.style.transform = "translate(150px, 450px)" 
40 el.style.transition = 'all 1s ease' 
41 //这里的done,其实就是afterEnter 这个函数,也就是说,done 是
//afterEnter 函数的引用
42 done() 
43 }, 
44 afterEnter(el){ 
45 //动画完成之后
46 this.flag = !this.flag 
47 } 
48 } 
49 }) 
50 </script> 
51 </body> 
52 </html>