Vue动画技术
过渡效果在交互体验中的重要性不言而喻。以往我们使用jQuery添加或移除元素的类,搭配CSS中定义好的样式,再引用一些JavaScript库之后,可以做出非常复杂、惊艳的动态效果,不过这一套方法仍略显烦琐。Vue.js内置了一套过渡系统,可以在元素从 DOM中插入或移除时自动应用过渡效果。Vue.,js会在适当的时机触发CSS 过渡或动画,用户也可以提供相应的JavaScript钩子函数在过渡过程中执行自定义DOM操作。
5
6
7
8
9
8.1 单元素组件过渡和动画
过渡效果就是在DOM元素进行切换、隐藏、插入和移除的时候加入一些酷炫的效果,使得过渡更加自然和美观,那么要想让组件实现动画,最基础的做法就是:
应用过渡效果,在需要加动画的地方,加入transition标签。代码示例如下:
<div id="app">
<transition>
<div v-if="show"></div>
</transition>
</div>
transition特性可以与以下资源一起搭配使用:
• v-if
• v-show
• v-for(v-for(只在插入和删除时触发,使用vue-animated-list插件)
• 动态组件(见“组件”一章)
8.1.1 初步Vue动画实例
我们先来看个简单基础的动画案例,大家看案例代码:
例8-1 Demo0801.html
1 <!DOCTYPE html>
2 <html lang="en">
3
4 <head>
5 <meta charset="UTF-8">
6 <meta http-equiv="X-UA-Compatible" content="IE=edge">
7 <meta name="viewport" content="width=device-width, initial-scale=1.0">
8 <title>动画</title>
9 <!-- 在线引入vue.js,必须引入否则无法使用vue-->
10 <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
11 <style>
12 #app {
13 text-align: center;
14 }
15
16 #app div {
17 width: 200px;
18 height: 200px;
19 margin: 30px auto;
20 background-color: bisque;
21 border: 1px solid bisque;
22 }
23
24 /* 进入和离开的状态 */
25 .fade-enter-active,
26 .fade-leave-active {
27 transition: opacity 1s;
28 }
29
30 /* .fade-enter定义进入过渡的开始状态 */
31 /* .fade-leave-to定义离开后的状态 */
32 .fade-enter,
33 .fade-leave-to {
34 opacity: 0;
35 }
36 </style>
37
38 </head>
39
40 <body>
41 <div id="app">
42 <button @click="show = !show">切换</button>
43 <br>
44 <transition name="fade">
45 <div v-if="show"></div>
46 </transition>
47 </div>
48
49
50 </body>
51
52
53 <script>
54
55
56 let vm = new Vue({
57 el: '#app',
58 data: {
59 show: true
60
61 },
62
63 })
64 </script>
65
66 </html>
程序的运行结果如下:
图 8- 1 入门案例
点击切换按钮,我们看到div框有一个淡入淡出的效果,原理如下:
当插入或删除包含在 transition 组件中的元素时,Vue 将会做以下处理:
1. 自动嗅探目标元素是否应用了 CSS 过渡或动画,如果是,在恰当的时机添加/删除 CSS 类名。
2. 如果过渡组件提供了 JavaScript 钩子函数,这些钩子函数将在恰当的时机被调用。
3. 如果没有找到 JavaScript 钩子并且也没有检测到 CSS 过渡/动画,DOM 操作 (插入/删除) 在下一帧中立即执行。
在案例中我们使用到了一些过渡的类名,现在来看看,在元素在进入/离开的过渡中,会有 6 个 class 切换。
1. v-enter:定义进入过渡的开始状态。在元素被插入之前生效,在元素被插入之后的下一帧移除。
2. v-enter-active:定义进入过渡生效时的状态。在整个进入过渡的阶段中应用,在元素被插入之前生效,在过渡/动画完成之后移除。这个类可以被用来定义进入过渡的过程时间,延迟和曲线函数。
3. v-enter-to:2.1.8 版及以上定义进入过渡的结束状态。在元素被插入之后下一帧生效 (与此同时 v-enter 被移除),在过渡/动画完成之后移除。
4. v-leave:定义离开过渡的开始状态。在离开过渡被触发时立刻生效,下一帧被移除。
5. v-leave-active:定义离开过渡生效时的状态。在整个离开过渡的阶段中应用,在离开过渡被触发时立刻生效,在过渡/动画完成之后移除。这个类可以被用来定义离开过渡的过程时间,延迟和曲线函数。
6. v-leave-to:2.1.8 版及以上定义离开过渡的结束状态。在离开过渡被触发之后下一帧生效 (与此同时 v-leave 被删除),在过渡/动画完成之后移除。
图 8- 2 过渡类名
特别说明,对于这些在过渡中切换的类名来说,如果你使用一个没有名字的 <transition>,则 v- 是这些类名的默认前缀。如果你使用了 <transition name="my-transition">,那么 v-enter 会替换为 my-transition-enter。
8.1.2 CSS过渡
我们常用的过渡都是使用 CSS 的样式规则实现过渡,借助css的样式实现酷炫的过渡效果。
我们来看8-2案例代码:
例8-2 Demo0802.html
1 <!DOCTYPE html>
2 <html lang="en">
3
4 <head>
5 <meta charset="UTF-8">
6 <meta http-equiv="X-UA-Compatible" content="IE=edge">
7 <meta name="viewport" content="width=device-width, initial-scale=1.0">
8 <title>动画</title>
9 <!-- 在线引入vue.js,必须引入否则无法使用vue-->
10 <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
11 <style>
12 #app {
13 text-align: center;
14 }
15
16 #app div {
17 width: 200px;
18 height: 200px;
19 margin: 30px auto;
20 background-color: bisque;
21 border: 1px solid bisque;
22 }
23
24 /* 可以设置不同的进入和离开动画 */
25 /* 设置持续时间和动画函数 */
26 .fade-enter-active {
27 transition: all .3s ease;
28 }
29
30 .fade-leave-active {
31 transition: all .8s cubic-bezier(1.0, 0.5, 0.8, 1.0);
32 }
33
34 .fade-enter,
35 .fade-leave-to {
36 transform: translateX(160px);
37 opacity: 0;
38 }
39 </style>
40
41 </head>
42
43 <body>
44 <div id="app">
45 <button @click="show = !show">切换</button>
46 <br>
47 <transition name="fade">
48 <div v-if="show"></div>
49 </transition>
50 </div>
51
52
53 </body>
54
55
56 <script>
57
58
59 let vm = new Vue({
60 el: '#app',
61 data: {
62 show: true
63
64 },
65
66 })
67 </script>
68
69 </html>
程序的运行结果跟例子8-1的区别是在水平位置上的偏移实现了平滑的过渡。我们可以借鉴之前学习的transform属性,灵活使用,还可以加入更多的样式规则,实现想要的效果。
在这我们需要注意,入场类名有三个:
<name>-enter:入场前
<name>-enter-active:入场持续的过程
<name>-enter-to:入场的结束
出场类名有三个:
<name>-leave:出场前
<name>-leave-active:出场持续的过程
<name>-leave-to:出场的结束
8.1.3 CSS过渡原理
在上一小节中,我们初步了解了Vue使用transition标签实现过渡的效果,接下来我们来看看具体的实现过程,以及原理。
首先,我们来看以下代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>动画</title>
<!-- 在线引入vue.js,必须引入否则无法使用vue-->
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<style>
#app {
text-align: center;
}
#app div {
width: 200px;
height: 200px;
margin: 30px auto;
background-color: bisque;
border: 1px solid bisque;
}
.fade-enter {
opacity: 0;
}
.fade-enter-active {
transition: opacity 1s;
}
</style>
</head>
<body>
<div id="app">
<button @click="show = !show">显示/隐藏</button>
<br>
<transition name="fade">
<div v-if="show"></div>
</transition>
</div>
</body>
<script>
let vm = new Vue({
el: '#app',
data: {
show: false
},
})
</script>
</html>
上面的代码我们只定义了进入前的类,以及进入的持续过程,我们通过过程看原理:
当动画执行的一瞬间,会在内部的div上增加两个class名字,分别是fade-enter和fade-enter-active,之所以是fade-开头,是因为transiton标签name是fade。当动画运行到第二帧的时候,Vue又会帮助你把fade-enter删除,然后添加一个fade-enter-to,再当动画执行到结束的一瞬间,又把fade-enter-active和fade-enter-to删除掉。
注意,在第一帧的时候,fade-enter-active和fade-enter同时存在,并且opacity=0,在第二帧的时候,fade-enter被删除,opacity恢复到原来的初始状态,就是1,在这个过程中,opacity发生了变化,所以fade-enter-active就让这个变化在3秒内完成,完成后进入到fade-enter-to的状态,但是我们没有定义则默认就是过程持续后的状态,opacity为1,此时进入的过渡状态已经完成,删除fade-enter-to和fade-enter-active,这就是元素进入的一个完整的过程。
但是如果要加入fade-enter-to,需要注意下图所示:
图 8- 3 注意讲解
以上讲解入场的过程原理,接下来看出场的过程原理:
加入以下代码:
#app {
text-align: center;
}
#app div {
margin: 30px auto;
background-color: bisque;
width: 200px;
height: 200px;
}
.fade-enter {
opacity: 0;
width: 200px;
height: 200px;
}
.fade-enter-active {
transition: opacity 1s, width 1s, height 1s;
}
.fade-enter-to {
border: 1px solid red;
width: 100px;
height: 100px;
}
.fade-leave {
opacity: 0.5;
width: 50px;
height: 50px;
}
.fade-leave-active {
transition: opacity 2s, width 2s, height 2s;
}
.fade-leave-to {
opacity: 0;
width: 200px;
height: 200px;
}
我们发现,进入效果完成后,我们定义了离开过渡的开始状态fade-leave,在data中show的值为false时,开始离开,此时会为类加上fade-leave和fade-leave-active状态,离开的持续过程完成后,进入结束状态fade-leave-to,此时fade-leave已经被删除,出场完成后,fade-leave-active和fade-leave-to被删除。
整个过程总结如下:
【v-enter】
定义进入过渡的开始状态。在元素被插入时生效,在下一个帧移除
【v-enter-active】
定义过渡的状态。在元素整个过渡过程中作用,在元素被插入时生效,在 transition 或 animation 完成之后移除。 这个类可以被用来定义过渡的过程时间,延迟和曲线函数
【v-enter-to】
定义进入过渡的结束状态。在元素被插入一帧后生效(与此同时 v-enter 被删除),在 transition 或 animation 完成之后移除
【v-leave】
定义离开过渡的开始状态。在离开过渡被触发时生效,在下一个帧移除
【v-leave-active】
定义过渡的状态。在元素整个过渡过程中作用,在离开过渡被触发后立即生效,在 transition 或 animation 完成之后移除。 这个类可以被用来定义过渡的过程时间,延迟和曲线函数
【v-leave-to】
定义离开过渡的结束状态。在离开过渡被触发一帧后生效(与此同时 v-leave 被删除),在 transition 或 animation 完成之后移除
以上就是我们整个过渡的过程和原理,接下来我们来看动画。
8.1.4 CSS动画
上一小节,我们实现了CSS过渡,通常过渡使用的是transition,本节课我们使用animation来加入动画效果。
例8-3 Demo0803.html
1 <!DOCTYPE html>
1 <html lang="en">
2
3 <head>
4 <meta charset="UTF-8">
5 <meta http-equiv="X-UA-Compatible" content="IE=edge">
6 <meta name="viewport" content="width=device-width, initial-scale=1.0">
7 <title>动画</title>
8 <!-- 在线引入vue.js,必须引入否则无法使用vue-->
9 <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
10 <style>
11 #app {
12 text-align: center;
13 }
14
15 #app div {
16
17 margin: 30px auto;
18 background-color: bisque;
19 width: 200px;
20 height: 200px;
21 border-radius: 50%;
22
23
24 }
25
26 .fade-enter-active {
27 animation: ani .5s;
28 }
29
30 .fade-leave-active {
31 animation: ani .5s reverse;
32 }
33
34 @keyframes ani {
35 0% {
36 transform: scale(0);
37 }
38
39 50% {
40 transform: scale(1.5);
41 }
42
43 100% {
44 transform: scale(1);
45 }
46 }
47 </style>
48
49 </head>
50
51 <body>
52 <div id="app">
53 <button @click="show = !show">显示/隐藏</button>
54 <br>
55 <transition name="fade">
56 <div v-if="show"></div>
57 </transition>
58 </div>
59 </body>
60 <script>
61 let vm = new Vue({
62 el: '#app',
63 data: {
64 show: false
65
66 },
67
68 })
69 </script>
70
71 </html>
图 8- 4 显示效果
例8-3中我们使用了animation给div进入和离开分别设置了缩放的动画效果,也可以借助之前学习的animation的知识实现更多酷炫的效果。
8.1.5 CSS动画和过渡同时使用
Vue 为了知道过渡的完成,必须设置相应的事件监听器。它可以是 transitionend 或 animationend ,这取决于给元素应用的 CSS 规则。如果使用其中任何一种,Vue 能自动识别类型并设置监听。
但是,在一些场景中,需要给同一个元素同时设置两种过渡动效,比如 animation 很快的被触发并完成了,而 transition 效果还没结束。在这种情况中,就需要使用 type 特性并设置 animation 或 transition 来明确声明需要 Vue 监听的类型,我们来看下面的案例:
例8-4 Demo0804.html
1 <!DOCTYPE html>
2 <html lang="en">
3
4 <head>
5 <meta charset="UTF-8">
6 <meta http-equiv="X-UA-Compatible" content="IE=edge">
7 <meta name="viewport" content="width=device-width, initial-scale=1.0">
8 <title>动画</title>
9 <!-- 在线引入vue.js,必须引入否则无法使用vue-->
10 <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
11 <style>
12 #app {
13 text-align: center;
14 }
15
16 #app div {
17
18 margin: 30px auto;
19 background-color: bisque;
20 width: 200px;
21 height: 200px;
22 border-radius: 50%;
23
24
25 }
26
27 .fade-enter,
28 .fade-leave-to {
29 opacity: 0;
30 }
31
32 .fade-enter-active,
33 .fade-leave-active {
34 transition: opacity 1s;
35 animation: bounce-in 5s;
36 }
37
38 @keyframes bounce-in {
39 0% {
40 transform: scale(0);
41 }
42
43 50% {
44 transform: scale(1.5);
45 }
46
47 100% {
48 transform: scale(1);
49 }
50 }
51 </style>
52
53 </head>
54
55 <body>
56 <div id="app">
57 <button @click="show = !show">显示/隐藏</button>
58 <br>
59 <transition name="fade" type="transition">
60 <div v-if="show"></div>
61 </transition>
62 </div>
63 </body>
64 <script>
65 let vm = new Vue({
66 el: '#app',
67 data: {
68 show: false
69
70 },
71
72 })
73 </script>
74
75 </html>
76
通过以上案例,我们发现如何设置type=‘transition’则主要是监听过渡为主,动画则不会执行1.5倍的缩放,因为过渡1s就完成了。如果type=’animation’则以监听动画为主,就会完整的执行动画,这一点大家在混合使用的时候注意。
8.1.6自定义类名
我们可以通过以下 attribute 来自定义过渡类名:
• 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 结合使用十分有用。
使用animate的步骤:
第一步:下载
https://daneden.github.io/animate.css
第二步:引入
在线引入:
<link href="https://cdn.jsdelivr.net/npm/animate.css@3.5.1" rel="stylesheet" type="text/css">
本地引入:
<link href="./animate.min.css" rel="stylesheet" type="text/css"/>
例8-5 Demo0805.html
1 <!DOCTYPE html>
2 <html lang="en">
3
4 <head>
5 <meta charset="UTF-8">
6 <meta http-equiv="X-UA-Compatible" content="IE=edge">
7 <meta name="viewport" content="width=device-width, initial-scale=1.0">
8 <title>动画</title>
9 <!-- 在线引入vue.js,必须引入否则无法使用vue-->
10 <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
11 <link href="https://cdn.jsdelivr.net/npm/animate.css@3.5.1" rel="stylesheet" type="text/css">
12 <style>
13 #app {
14 text-align: center;
15 }
16
17 #app div {
18
19 margin: 30px auto;
20 background-color: bisque;
21 width: 200px;
22 height: 200px;
23 border-radius: 50%;
24
25
26 }
27
28 .fade-enter,
29 .fade-leave-to {
30 opacity: 0;
31 }
32
33 .fade-enter-active,
34 .fade-leave-active {
35 transition: opacity 1s;
36 animation: bounce-in 5s;
37 }
38
39 @keyframes bounce-in {
40 0% {
41 transform: scale(0);
42 }
43
44 50% {
45 transform: scale(1.5);
46 }
47
48 100% {
49 transform: scale(1);
50 }
51 }
52 </style>
53
54 </head>
55
56 <body>
57 <div id="app">
58 <button @click="show = !show">显示/隐藏</button>
59 <br>
60 <transition name="fade" enter-active-class="animated tada" leave-active-class="animated bounceOutRight">
61 <div v-if="show"></div>
62 </transition>
63 </div>
64 </body>
65 <script>
66 let vm = new Vue({
67 el: '#app',
68 data: {
69 show: false
70
71 },
72
73 })
74 </script>
75
76 </html>
77
至此,便可以实现vue+animate.css动画库的结合使用。它的优势,像某些比较复杂的动画效果,此时便省去手写过程,直接引入使用现有动画库即可,大大提高了开发效率。
注意:
1、必须使用transition标签的自定义动画名属性,即enter-active-class和leave-active-class;
2、使用时必须加入animated类名。
8.1.7初始渲染过渡
如果想在页面初始化时渲染动画效果,此时需要用到appear呈现属性和appear-active-class呈现过渡属性,语法如下:
<transition appear>
<!-- ... -->
</transition>
如果只写appear,则初始化动画默认和进入/离开过渡效果一样,同样也可以自定义 CSS 类名。
<transition
appear
appear-class="custom-appear-class"
appear-to-class="custom-appear-to-class" (2.1.8+)
appear-active-class="custom-appear-active-class"
>
<!-- ... -->
</transition>
但是要注意,它只是在第一次渲染的时候才会起作用。
例8-6 Demo0806.html
1 <!DOCTYPE html>
2 <html lang="en">
3
4 <head>
5 <meta charset="UTF-8">
6 <meta http-equiv="X-UA-Compatible" content="IE=edge">
7 <meta name="viewport" content="width=device-width, initial-scale=1.0">
8 <title>动画</title>
9 <!-- 在线引入vue.js,必须引入否则无法使用vue-->
10 <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
11 <link href="https://cdn.jsdelivr.net/npm/animate.css@3.5.1" rel="stylesheet" type="text/css">
12
13 <style>
14 #app div {
15 width: 200px;
16 height: 200px;
17 background-color: antiquewhite;
18
19 }
20
21 .fade-enter,
22 .fade-leave-to {
23 opacity: 0;
24 }
25
26 .fade-enter-active,
27 .fade-leave-active {
28 transition: opacity 3s;
29 }
30 </style>
31
32 </head>
33
34 <body>
35 <div id="app">
36 <transition name="fade" enter-active-class="animated swing fade-enter-active"
37 leave-active-class="animated swing fade-leave-active">
38 <div v-show="show">
39 我是要显示的内容
40 </div>
41 </transition>
42 <button @click="show=!show">点击</button>
43 </div>
44 </body>
45 <script>
46 var count = 0;
47 new Vue({
48 el: '#app',
49 data: {
50 show: true
51 },
52 methods: {
53
54 }
55 })
56 </script>
57
58 </html>
例8-6中,在页面初始化时候是没有动画效果的,点击按钮的时候才会触发动画;如果想要在页面初始化就有动画效果,就必须加appear,也可以指定初始化动画,如下示例:
<div id="app">
<transition appear appear-class="animated shakeY" appear-to-class="animated wobble"
appear-active-class="animated jello" name="fade" enter-active-class="animated swing fade-enter-active"
leave-active-class="animated swing fade-leave-active">
<div v-show="show">
我是要显示的内容
</div>
</transition>
<button @click="show=!show">点击</button>
</div>
但是这里有一些问题:关于appear-class、 appear-to-class、 appear-active-class的相同属性那个起作用的问题。
四种情况:(与他们在style中的排列顺序有关系)
1、appear-class、 appear-to-class、 appear-active-class或者 appear-to-class、appear-class、 appear-active-class的排列顺序,此时只有appear-active-class的属性起作用。
2、appear-active-class、appear-class、 appear-to-class
此时appear-active-class的不起作用,由appear-class过渡到appear-to-class属性。
3、appear-class、appear-active-class、 appear-to-class
此时appear-class属性不起作用,由appear-active-class过渡到 appear-to-class属性。
4、 appear-to-class、 appear-active-class、appear-class
此时appear-to-class不起作用,由appear-class过渡到 appear-active-class属性。
8.1.8过渡时间设置
在很多情况下,Vue 可以自动得出过渡效果的完成时机。默认情况下,Vue 会等待其在过渡效果的根元素的第一个 transitionend 或 animationend 事件。然而也可以不这样设定——比如,我们可以拥有一个精心编排的一系列过渡效果,其中一些嵌套的内部元素相比于过渡效果的根元素有延迟的或更长的过渡效果。
在这种情况下你可以用 <transition> 组件上的 duration prop 定制一个显性的过渡持续时间 (以毫秒计):
<transition :duration="1000">...</transition>
你也可以定制进入和移出的持续时间:
<transition :duration="{ enter: 500, leave: 800 }">
...
</transition>
8.2 JavaScript钩子函数
上一节我们使用CSS实现的过渡和动画,本节课讲解使用JavaScript钩子函数实现过渡和动画。
JavaScript钩子函数完整过程如下:
• enter过程:
before-enter:进入过渡前;
enter:过渡运行时;
after-enter:过渡完成后;
enter-cancelled:过渡被打断;
• leave过程:
before-leave:离开过渡运行前;
leave:离开过渡运行时;
after-leave:离开过渡运行后;
leave-cancelled:离开过渡被打断;
使用示例代码:
<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"
>
<!-- ... -->
</transition>
/ ...
methods: {
// --------
// 进入中
// --------
beforeEnter: function (el) {
// ...
},
// 当与 CSS 结合使用时
// 回调函数 done 是可选的
enter: function (el, done) {
// ...
done()
},
afterEnter: function (el) {
// ...
},
enterCancelled: function (el) {
// ...
},
// --------
// 离开时
// --------
beforeLeave: function (el) {
// ...
},
// 当与 CSS 结合使用时
// 回调函数 done 是可选的
leave: function (el, done) {
// ...
done()
},
afterLeave: function (el) {
// ...
},
// leaveCancelled 只用于 v-show 中
leaveCancelled: function (el) {
// ...
}
}
接下来我们来一个一个的看:
1.过渡前状态
示例代码:
<style>
#app div {
width: 200px;
height: 200px;
background-color: antiquewhite;
}
</style>
</head>
<body>
<div id="app">
<transition @before-enter="beforEnter">
<div v-show="show">
我是要显示的内容
</div>
</transition>
<button @click="show=!show">点击</button>
</div>
</body>
<script>
var count = 0;
new Vue({
el: '#app',
data: {
show: true
},
methods: {
//进入过度前把dom元素设置为字体为红色
beforEnter(el) {
console.log('beforEnter触发了');
el.style.color = "red";
}
}
})
</script>
程序运行效果如下:
图 8- 5 入场前过渡
该示例代码中钩子函数参数el指的时过渡的元素div,给div设置过渡前的样式。
2.入场钩子enter过渡进入完成时状态
enter钩子和before-enter稍微有些差异,enter会接受两个参数,语法为enter(el,done),done为回调函数。当before-enter触发完毕后的下一帧,将会真正运行动画效果,整个动画效果也将放到enter这个钩子阶段。
案例:2s后元素字体颜色有红色编程蓝色
示例代码:
<div id="app">
<transition @before-enter="beforEnter" @enter="enterFun">
<div v-show="show">
我是要显示的内容
</div>
</transition>
<button @click="show=!show">点击</button>
</div>
enterFun(el, done) {
setInterval(() => {
el.style.color = "blue";
}, 2000);
done();//告知动画结束
}
3.入场钩子after-enter过渡完成后
执行时机,在enter过渡进入完成后触发done()回调函数,告知vue动画执行完毕,下一步执行after-enter过渡完成后钩子函数。
示例代码:
<body>
<div id="app">
<transition @before-enter="beforEnter" @enter="enterFun" @after-enter="afterFn">
<div v-show="show">
我是要显示的内容
</div>
</transition>
<button @click="show=!show">点击</button>
</div>
</body>
<script>
var count = 0;
new Vue({
el: '#app',
data: {
show: true
},
methods: {
//进入过度前把dom元素设置为字体为红色
beforEnter(el) {
console.log('beforEnter触发了');
el.style.color = "red";
},
enterFun(el, done) {
setTimeout(() => {
el.style.color = "blue";
}, 2000);
setTimeout(() => {
done();//告知动画结束后才会调用下一帧的afterFn
}, 4000);
},
afterFn(el) {
el.style.color = "purple";
}
}
})
</script>
注意:进入动画完成过渡后,要调用done,这样才可以进入下一帧。
4.入场钩子enter-cancelled过渡被打断
示例代码:
<div id="app">
<transition @before-enter="beforEnter" @enter="enterFun" @after-enter="afterFn" @enter-cancelled="calFn">
<div v-show="show">
我是要显示的内容
</div>
</transition>
<button @click="show=!show">点击</button>
</div>
calFn() {
console.log('calFn');
}
当过渡开始的时候,不等过渡执行完毕,打断过渡就会执行enter-cancelled。
出场钩子与入场钩子语法类似,如下:
1、before-leave(el)离开过渡运行前
2、leave(el,done)离开过渡运行时
3、after-leave(el)离开过渡运行后
4、leave-cancelled(el)离开过渡被打断时
注意:leave和enter一样,接受两个参数,而且要执行下一帧,必须显示调用done().
8.3 多个元素过渡
如果transition 中包含多个元素,我们来看如何设置:
样式部分设置:
1 <style>
2 .v-enter,.v-leave-to{
3 opacity: 0;
4 }
5 .v-enter-active,.v-leave-active{
6 transition: opacity .5s;
7 }
8 </style><!-- 分页组件 -->
Html结构部分:
1 <div id="app"><!-- 这有2个div,点击按钮切换显示div内容, 但是需要注意:VUE默认会复用dom元素,导致过渡效果不显示, 解决: 添加唯一值key属性可以标识独立的dom,避免复用 mode是transition自带的属性,可以是out-in 或者 in-out -->
2 <transition mode="out-in">
3 <div v-if="show" key="hello">hello vue</div>
4 <div v-else key="Bye">Bye Vue</div>
5 </transition>
6 <button @click="handleClick">change</button>
7 </div>
Script部分:
1 <script>
2 var vm = new Vue({
3 el: '#app',
4 data:{
5 show: true
6 },
7 methods:{
8 handleClick:function(){
9 this.show = !this.show;
10 }
11 }
12 })
13 </script>
以上案例中,要注意,transition中如果多个元素切换,则必须使用key,避免复用。
mode是transition自带的属性,可以是out-in(先出后进) 或者 in-out(先进后出)。
8.4 多个组件过渡
在上一节中,transition中有多个html元素,如果transition中有多个自定义组件时候该如何过渡呢,我们看以下代码:
样式部分设置:
1 <style>
2 .v-enter,.v-leave-to{
3 opacity: 0;
4 }
5 .v-enter-active,.v-leave-active{
6 transition: opacity .5s;
7 }
8 </style>
Html结构部分:
1 <div id="app">
2 <transition mode="in-out">
3 <!-- 动态组件 -->
4 <component :is="type"></component>
5 </transition>
6 <button @click="handleClick">change</button>
7 </div>
8
Script部分:
14 <script>
15 Vue.component('child',{
16 template: '<div>child</div>'
17 });
18 Vue.component('child-one',{
19 template: '<div>child-one</div>'
20 })
21 var vm = new Vue({
22 el: '#app',
23 data:{
24 type: 'child'
25 },
26 methods:{
27 handleClick:function(){
28 this.type = (this.type === 'child'?'child-one' : 'child');
29 }
30 }
31 })
32 </script>
该案例中,我们使用动态组件实现切换,其实跟多元素本质是一样的。
8.5 列表过渡
如果transition中同时有多个元素或者组件,我们应该使用transition-group,接下来我们来看案例:
例8-6 Demo0806.html
1
2 <!DOCTYPE html>
3 <html lang="en">
4
5 <head>
6 <meta charset="UTF-8">
7 <meta http-equiv="X-UA-Compatible" content="IE=edge">
8 <meta name="viewport" content="width=device-width, initial-scale=1.0">
9 <title>动画</title>
10 <!-- 在线引入vue.js,必须引入否则无法使用vue-->
11 <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
12 <link href="https://cdn.jsdelivr.net/npm/animate.css@3.5.1" rel="stylesheet" type="text/css">
13 <style>
14 .v-enter,
15 .v-leave-to {
16 opacity: 0;
17 }
18
19 .v-enter-active,
20 .v-leave-active {
21 transition: opacity 1s;
22 }
23 </style>
24
25 </head>
26
27 <body>
28 <div id="app">
29 <transition-group>
30 <div v-for="item of list" :key="item.id">
31 {{item.title}}-{{item.id}}
32 </div>
33 </transition-group>
34 <button @click="handleAdd">Add</button>
35 </div>
36 </body>
37 <script>
38 var count = 0;
39 new Vue({
40 el: '#app',
41 data: {
42 list: []
43 },
44 methods: {
45 handleAdd: function () {
46 this.list.push({
47 id: count++,
48 title: 'hello vue'
49 })
50 }
51 }
52 })
53 </script>
54
55 </html>
图 8- 6 列表效果
在该案例中,我们发现每添加一条数据,都有动画过渡。如果使用v-for,并且循环的每个列表在添加和移除的时候需要设置过渡和动画则必须使用transition-group。
8.6 可复用过渡
过渡可以通过 Vue 的组件系统实现复用。我们可以把一个封装好动画的组件,实现在任何页面的复用。
下面我们来看步骤:
第一步:过渡组件建立:
Vue.component('my-special-transition', {
template: `
<transition name="very-special-transition" mode="out-in" v-on:before-enter="beforeEnter" @enter="enterFn"
v-on:after-enter="afterEnter">
<slot v-if='status'></slot>
</transition>
`,
props: ['status'],
methods: {
beforeEnter: function (el) {
el.style.color = "red";
},
enterFn(el, done) {
setTimeout(() => {
el.style.color = 'green';
}, 2000);
setTimeout(() => {
done();
}, 4000);
},
afterEnter: function (el) {
el.style.color = "blue";
}
}
})
在这我们使用的插槽,因为不确定我们要过渡的内容,在slot上加上v-if=’status’,这个status的值是从根组件上传过来的。
第二步:调用
示例代码:
<div id="app">
<button @click="show = !show">切换</button>
<my-special-transition :status="show">
<p>世界,你好</p>
</my-special-transition>
</div>
完整代码:
<body>
<div id="app">
<button @click="show = !show">切换</button>
<my-special-transition :status="show">
<p>世界,你好</p>
</my-special-transition>
</div>
<script>
Vue.component('my-special-transition', {
template: `
<transition name="very-special-transition" mode="out-in" v-on:before-enter="beforeEnter" @enter="enterFn"
v-on:after-enter="afterEnter">
<slot v-if='status'></slot>
</transition>
`,
props: ['status'],
methods: {
beforeEnter: function (el) {
el.style.color = "red";
},
enterFn(el, done) {
setTimeout(() => {
el.style.color = 'green';
}, 2000);
setTimeout(() => {
done();
}, 4000);
},
afterEnter: function (el) {
el.style.color = "blue";
}
}
})
new Vue({
el: '#app',
data: {
show: false
}
});
</script>
总结:复用过渡组件主要是借助于父子组件的传值。
8.7 案例使用
下面我们来使用学习的过渡动画实现一个简单的小案例:
目标:
1. 显示列表;
2. 添加列表动态添加;
3. 点击列表每一项实现动画删除;
例8-7 Demo0807.html
1 <!DOCTYPE html>
2 <html lang="en">
3
4 <head>
5 <meta charset="UTF-8">
6 <meta name="viewport" content="width=device-width, initial-scale=1.0">
7 <meta http-equiv="X-UA-Compatible" content="ie=edge">
8 <title>Document</title>
9 <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
10 <style>
11 ul {
12 list-style: none;
13 }
14
15 li {
16 border: 1px dashed green;
17 height: 50px;
18 line-height: 50px;
19 margin: 5px;
20
21 }
22
23 li:hover {
24 background-color: brown;
25 transition: all 1s ease;
26 }
27
28 .v-enter,
29 .v-leave-to {
30 transform: translateY(70px);
31 }
32
33 .v-enter-active,
34 .v-leave-active {
35 transition: all 0.5s ease;
36 }
37
38 .v-move {
39 transition: all 0.5s ease;
40 }
41 </style>
42 </head>
43
44 <body>
45 <div id="app">
46 <label for="id">
47 <input type="text" v-model="pid" id="id">
48 </label>
49 <label for="name">
50 <input type="text" v-model="pname" id="name">
51 </label>
52 <label>
53 <input type="button" value="添加" @click="addfn">
54 </label>
55 <ul>
56 <transition-group>
57 <li v-for="(p,i) in list" :key="p.id" @click="del(i)">
58 {{p.id}} ========== {{p.name}}
59 </li>
60 </transition-group>
61
62 </ul>
63 </div>
64 <script>
65 //创建Vue实例,得到 ViewModel
66 var vm = new Vue({
67 el: '#app',
68 data: {
69 pid: "",
70 pname: "",
71 list: [
72 { id: 1001, name: "陈羽凡" },
73 { id: 1002, name: "胡海泉" },
74 { id: 1003, name: "刘德华" },
75 { id: 1004, name: "成龙" }
76 ]
77 },
78 methods: {
79 addfn() {
80 this.list.push({ id: this.pid, name: this.pname });
81 this.pid = this.pname = "";
82 },
83 del(i) {
84 this.list.splice(i, 1);
85
86 }
87 }
88 });
89 </script>
90 </body>
91
92 </html>
程序运行效果如下:
图 8- 7 过渡效果
本案例,在添加的时候设置了过渡效果,在点击每一条的时候实现过渡删除每一条目;核心代码主要是使用列表过渡。
8.8 本章小结
• 单元素组件的过渡使用transition标签,以及v-if,v-show,结合Vue过渡实现组件的切换和过渡。动画主要使用CSS动画和第三方动画库。
• transition里面也可以放多个html元素实现过渡,主要是借助v-if-,v-els--if;
• javascript的钩子主要有进入过渡的过程以及离开过渡的过程,整个过程包括八个钩子函数;
• Transition里面也可以放置动态组件,借助于component标签;
• 借助于Vue的组件系统,也可以在封装组件的时候加上过渡,这样就形成了可复用的过渡组件。
8.9 理论试题与实践练习
1.编程题
在图书管理系统的基础上:
1.%2 实现页面打开的时候,添加界面隐藏;
2.%2 点击添加按钮的时候实现组件过渡出现;
3.%2 点击删除的时候实现动画删除;
- 点赞
- 收藏
- 关注作者
评论(0)