# 过渡与动画
前端交互效果往往显得比较重要,一个产品的良好体验,交互效果起到了很大作用。Vue 在插入、更新或者移除 DOM 时,提供多种不同方式的应用过渡动画效果。# 过渡的 class
基本示例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>vue</title>
<script src="https://labfile.oss.aliyuncs.com/courses/1262/vue.min.js"></script>
<style>
/* 定义进入和离开过渡生效时的状态 */
.fade-enter-active,
.fade-leave-active {
transition: opacity 0.5s;
}
/* 定义过渡的开始和结束状态 */
.fade-enter,
.fade-leave-to {
opacity: 0;
}
</style>
</head>
<body>
<div id="app">
<!-- 点击显示隐藏 切换 按钮 改变实例 show数据的值 !=== 取反 -->
<button v-on:click="show = !show">Toggle</button>
<!-- transition ’见名知意‘ 这是一个 Vue 内置封装的 动画组件 他可以指定被他包囊 元素的交互效果 -->
<!-- name 就是动画过渡名字 fade 这个是内置动画过渡名-->
<transition name="fade">
<!-- v-if 如果show 为true 就渲染 -->
<p v-if="show">hello syl</p>
</transition>
</div>
<script>
var app = new Vue({
el: "#app",
data() {
return {
show: true,
};
},
});
</script>
</body>
</html>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
运行效果:
上面看了一个基础示例,我们是可以通过特定的 css 来控制动画或者过渡的全过程,我们来学习一下过渡的类名
v-enter
:定义进入过渡的开始状态。在元素被插入之前生效,在元素被插入之后的下一帧移除。v-enter-active
:定义进入过渡生效时的状态。在整个进入过渡的阶段中应用,在元素被插入之前生效,在过渡/动画完成之后移除。这个类可以被用来定义进入过渡的过程时间,延迟和曲线函数。v-enter-to
: 定义进入过渡的结束状态。在元素被插入之后下一帧生效 (与此同时v-enter
被移除),在过渡/动画完成之后移除。v-leave
: 定义离开过渡的开始状态。在离开过渡被触发时立刻生效,下一帧被移除。v-leave-active
:定义离开过渡生效时的状态。在整个离开过渡的阶段中应用,在离开过渡被触发时立刻生效,在过渡/动画完成之后移除。这个类可以被用来定义离开过渡的过程时间,延迟和曲线函数。v-leave-to
: 定义离开过渡的结束状态。在离开过渡被触发之后下一帧生效 (与此同时v-leave
被删除),在过渡/动画完成之后移除。
一般套路,可以根据自己需求自由组合定制:
.v-enter,
.v-leave-to {
/* 定义元素默认状态 例如:opacity:0*/
}
.v-enter-to,
.v-leave {
/* 定义元素激活时状态 例如:opacity:1*/
}
.v-enter-active,
.v-leave-active {
/* 定义过渡或动画,在过渡中的状态 */
/*
最常用的就是在这里面指定过渡动画 时间/延迟/曲线函数
transition:opacity:1s 1s ease-in-out
*/
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# CSS 过渡
上面其实就是一个 CSS 过渡实例,根据上面介绍的过渡类名和一般套路,自己来写一个过渡。
打造 快进缓出 过渡效果:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>vue</title>
<script src="https://labfile.oss.aliyuncs.com/courses/1262/vue.min.js"></script>
<style>
.my-transition-enter,
.my-transition-leave-to {
/* 定义元素默认状态 例如:opacity:0 */
opacity: 0;
}
.my-transition-enter-to,
.my-transition-leave {
/* 定义元素激活时状态 例如:opacity:1*/
opacity: 1;
}
.my-transition-enter-active {
/* 默认到激活状态过渡,0.5s 快速进入 */
transition: opacity 0.5s;
}
.my-transition-leave-active {
/* 激活到默认状态过渡 2s 缓出过渡打造 */
transition: opacity 2s;
}
</style>
</head>
<body>
<div id="app">
<!-- 点击显示隐藏 切换 按钮 改变实例 show数据的值 '取反' -->
<button v-on:click="show = !show">快进缓出过渡</button>
<!-- transition ’见名知意‘ 这是一个 Vue 内置封装的 动画组件 他可以指定被他包囊 元素的交互效果 -->
<!--自定义一个 my-transition 过渡-->
<transition name="my-transition">
<!-- v-if 如果show 为true 就渲染 -->
<p v-if="show">hello syl</p>
</transition>
</div>
<script>
var app = new Vue({
el: "#app",
data() {
return {
show: false,
};
},
});
</script>
</body>
</html>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
运行效果:
# CSS 动画
开发中不仅仅只需要过渡效果,往往是两者的结合,CSS 动画用法同 CSS 过渡一样。如果对 CSS3 动画不了解的可以进入 CSS 基础课程学习一下。
放大缩小动画:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>vue</title>
<script src="https://labfile.oss.aliyuncs.com/courses/1262/vue.min.js"></script>
<style>
#app {
width: 200px;
height: 200px;
overflow: hidden;
}
.bounce-enter-active {
animation: bounce-in 0.5s;
}
.bounce-leave-active {
animation: bounce-in 0.5s reverse;
}
@keyframes bounce-in {
0% {
transform: scale(0);
}
50% {
transform: scale(1.5);
}
100% {
transform: scale(1);
}
}
</style>
</head>
<body>
<div id="app">
<button @click="show = !show">css动画</button>
<transition name="bounce">
<p v-if="show">hello syl hello syl hello syl</p>
</transition>
</div>
<script>
var app = new Vue({
el: "#app",
data() {
return {
show: true,
};
},
});
</script>
</body>
</html>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
运行效果:
# 自定义过渡类名
我们可以通过以下特性来自定义过渡类名:
enter-class
enter-active-class
enter-to-class
leave-class
leave-active-class
leave-to-class
这对于 Vue 的过渡系统和其他第三方 CSS 动画库,如 Animate.css (opens new window) 结合使用十分有用。
例子,Vue 结合 Animate.css (opens new window) :
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>vue</title>
<script src="https://labfile.oss.aliyuncs.com/courses/1262/vue.min.js"></script>
<!-- 引入animate.css -->
<link
href="https://cdn.jsdelivr.net/npm/animate.css@3.5.1"
rel="stylesheet"
type="text/css"
/>
</head>
<body>
<div id="app">
<button @click="show = !show">Toggle render</button>
<!-- 自定义过渡的类名 animate.css动画库的类名 -->
<transition
name="custom-classes-transition"
enter-active-class="animated tada"
leave-active-class="animated bounceOutRight"
>
<p v-if="show">hello</p>
</transition>
</div>
<script>
var app = new Vue({
el: "#app",
data() {
return {
show: true,
};
},
});
</script>
</body>
</html>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
运行结果:
# 同时使用过渡与动画
Vue 为了知道过渡的完成,必须设置相应的事件监听器。它可以是 transitionend
或 animationend
,这取决于给元素应用的 CSS 规则。如果你使用其中任何一种,Vue 能自动识别类型并设置监听。
但是,在一些场景中,你需要给同一个元素同时设置两种过渡动效,比如 animation
很快的被触发并完成了,而 transition
效果还没结束。在这种情况下,你就需要使用 type
特性并设置 animation
或 transition
来明确声明你需要 Vue 监听的类型。
# 显性过渡时间
我们可以编排一系列过渡效果,其中一些嵌套的内部元素相比于过渡效果的根元素有延迟的或更长的过渡效果。
<transition>
组件上的 duration
属性定制一个显性的过渡持续时间 (以毫秒计),形成先后顺序的动画队列。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>vue</title>
<script src="https://labfile.oss.aliyuncs.com/courses/1262/vue.min.js"></script>
<style>
#app {
width: 200px;
height: 200px;
overflow: hidden;
}
.bounce-enter-active {
animation: bounce-in 0.5s;
}
.bounce-leave-active {
animation: bounce-in 0.5s reverse;
}
@keyframes bounce-in {
0% {
transform: scale(0);
}
50% {
transform: scale(1.5);
}
100% {
transform: scale(1);
}
}
</style>
</head>
<body>
<div id="app">
<button @click="show = !show">动画队列</button>
<transition name="bounce" :duration="2000">
<p v-if="show">hello syl hello syl hello syl</p>
</transition>
<transition name="bounce" :duration="1500">
<p v-if="show">hello syl hello syl hello syl</p>
</transition>
<transition name="bounce" :duration="1000">
<p v-if="show">hello syl hello syl hello syl</p>
</transition>
<transition name="bounce" :duration="500">
<p v-if="show">hello syl hello syl hello syl</p>
</transition>
</div>
<script>
var app = new Vue({
el: "#app",
data() {
return {
show: true,
};
},
});
</script>
</body>
</html>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
运行效果:
# JavaScript 动画钩子
使用动画钩子你更能掌控动画的全过程,更好的与 JavaScript 动画库 结合。
<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>
2
3
4
5
6
7
8
9
10
11
前面四个进入动画钩子,后面四个离开动画钩子
// ...
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) {
// ...
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
示例使用 velocity.js 动画库和动画钩子函数,打造精细动画:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>vue</title>
<script src="https://labfile.oss.aliyuncs.com/courses/1262/vue.min.js"></script>
<!-- velocity.js 引入 -->
<script src="https://labfile.oss.aliyuncs.com/courses/1379/velocity.min.js"></script>
</head>
<body>
<div id="app">
<button @click="show = !show">Toggle</button>
<transition
v-on:before-enter="beforeEnter"
v-on:enter="enter"
v-on:leave="leave"
v-bind:css="false"
>
<p v-if="show">Demo</p>
</transition>
</div>
<script>
var app = new Vue({
el: "#app",
data() {
return {
show: false,
};
},
methods: {
beforeEnter: function (el) {
el.style.opacity = 0;
el.style.transformOrigin = "left";
},
enter: function (el, done) {
Velocity(
el,
{
opacity: 1,
fontSize: "1.4em",
},
{
duration: 300,
}
);
Velocity(
el,
{
fontSize: "1em",
},
{
complete: done,
}
);
},
leave: function (el, done) {
Velocity(
el,
{
translateX: "15px",
rotateZ: "50deg",
},
{
duration: 600,
}
);
Velocity(
el,
{
rotateZ: "100deg",
},
{
loop: 2,
}
);
Velocity(
el,
{
rotateZ: "45deg",
translateY: "30px",
translateX: "30px",
opacity: 0,
},
{
complete: done,
}
);
},
},
});
</script>
</body>
</html>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
运行效果:
# 初始化过渡
我们想要页面初次渲染就有一个过渡效果,可以通过 appear
特性设置节点在初始渲染的过渡。 使用 F5 刷新查看效果:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>vue</title>
<script src="https://labfile.oss.aliyuncs.com/courses/1262/vue.min.js"></script>
<style>
#app {
width: 200px;
height: 200px;
overflow: hidden;
}
/* 自定义初始化css */
.bounce-enter-active,
.bounce-appear-active-class {
animation: bounce-in 0.5s;
}
@keyframes bounce-in {
0% {
transform: scale(0);
}
50% {
transform: scale(1.5);
}
100% {
transform: scale(1);
}
}
</style>
</head>
<body>
<div id="app">
<!-- 自定义初始化渲染过渡和动画 -->
<transition
appear
appear-class="bounce-appear-class"
appear-to-class="bounce-appear-to-class"
appear-active-class="bounce-appear-active-class"
>
<p>可以通过 appear 特性设置节点在初始渲染的过渡</p>
</transition>
</div>
<script>
var app = new Vue({
el: "#app",
data() {
return {
show: true,
};
},
});
</script>
</body>
</html>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
运行结果:
注意: 和动画钩子一样,该特性也提供钩子函数。
<transition
appear
v-on:before-appear="customBeforeAppearHook"
v-on:appear="customAppearHook"
v-on:after-appear="customAfterAppearHook"
v-on:appear-cancelled="customAppearCancelledHook"
>
</transition>
2
3
4
5
6
7
8
# 多个元素过渡
多个元素过渡,可以使用 v-if
/v-else
,确定那个元素渲染,但是注意为相同标签的元素绑定 key 值,提高性能。
丝滑开关切换例子:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>vue</title>
<script src="https://labfile.oss.aliyuncs.com/courses/1262/vue.min.js"></script>
<style>
#app {
position: relative;
height: 18px;
}
button {
position: absolute;
}
.fade-enter-active,
.fade-leave-active {
transition: all 1s;
}
.fade-enter,
.fade-leave-active {
opacity: 0;
}
.fade-enter {
transform: translateX(31px);
}
.fade-leave-active {
transform: translateX(-31px);
}
</style>
</head>
<body>
<div id="app">
<transition name="fade">
<button v-if="docState === 'saved'" key="saved" @click="handleClick">
Edit
</button>
<button v-if="docState === 'edited'" key="edited" @click="handleClick">
Save
</button>
</transition>
</div>
<script>
var app = new Vue({
el: "#app",
data() {
return {
docState: "saved",
};
},
//点击切换docState值
methods: {
handleClick: function () {
if (this.docState == "saved") {
this.docState = "edited";
} else {
this.docState = "saved";
}
},
},
});
</script>
</body>
</html>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
运行效果:
# 综合小练习
移动端菜单:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>syl-vue</title>
<script src="https://labfile.oss.aliyuncs.com/courses/1262/vue.min.js"></script>
<style>
* {
padding: 0;
margin: 0;
}
a {
text-decoration: none;
}
ul {
list-style: none;
}
nav {
position: absolute;
top: 0;
left: 0;
bottom: 0;
right: 0;
margin: auto;
list-style: none;
width: 175px;
height: 367px;
border: 1px solid #000;
border-radius: 10px;
overflow: hidden;
}
nav .nav-header {
height: 40px;
background: #9966cc;
border-top-right-radius: 10px;
border-top-left-radius: 10px;
display: flex;
flex-direction: column;
transition: all 0.5s;
}
.line1,
.line2,
.line3 {
width: 20px;
height: 1px;
background: black;
margin: 5px 10px;
align-self: flex-end;
transition: all 0.5s;
}
.nav-header.active .line1 {
transition: all 0.4s ease-in-out;
transform: rotate(-45deg) translate(-10px, 5px);
}
.nav-header.active .line2 {
opacity: 0;
}
.nav-header.active .line3 {
transition: all 0.4s;
transform: rotate(45deg) translate(-9px, -5px);
}
nav ul {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
nav ul li {
width: 100%;
padding: 10px 0px;
text-align: center;
}
.bounce-enter-active {
animation: bounce-in 0.5s;
}
.bounce-leave-active {
animation: bounce-in 0.5s reverse;
}
@keyframes bounce-in {
0% {
transform: translateX(300px);
}
100% {
transform: translateX(0px);
}
}
</style>
</head>
<body>
<div id="app">
<nav>
<div class="nav-header" @click="show=!show" :class="{active:show}">
<div class="line1"></div>
<div class="line2"></div>
<div class="line3"></div>
</div>
<transition name="bounce">
<ul v-if="show">
<li v-for="nav in navbar" :key="nav">{{nav}}</li>
</ul>
</transition>
</nav>
</div>
<script>
var app = new Vue({
el: "#app",
data() {
return {
navbar: ["HOME", "CONTACT", "ABOUT", "INFO"],
show: false,
};
},
});
</script>
</body>
</html>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
运行效果: