Vue核心应用(三)— 动画

前言

元素的显示隐藏都可以增加动画效果v-ifv-showv-for、路由切换等操作。

常见的增加动画的方式有 animationtransitionjs编写动画

css3动画

我们先要具体掌握一下每个样式的触发阶段

1
2
3
4
<div @click="show()">显示/隐藏</div>
<transition>
<div class="content" v-if="isShow"></div>
</transition>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
.content{
width: 100px;height: 100px;background: red;;;
}
.v-enter{ /*进入前*/
background: blue;
opacity: 0;
}
.v-enter-active{ /*进入中*/
transition: all 2s linear;
}
.v-enter-to{ /*目标*/
background: black;
}
/* 回到默认效果 红色 */
.v-leave{ /*开始离开*/
background: yellow;
}
.v-leave-active{ /*离开中*/
transition: all 2s linear;
}
.v-leave-to{ /*目标*/
background: green;
}
/*元素隐藏*/

我们可以使用name属性来更改默认v-前缀

配合animate.css使用

安装animate.css

1
npm install animate.css
1
2
3
4
5
6
7
8
9
10
11
12
<link rel="stylesheet" href="node_modules/animate.css/animate.css">
<style >
.content{
background: red;width: 100px;height: 100px;
}
.v-enter-active{
animation:bounceIn 1s ease-in;
}
.v-leave-active{
animation:bounceOut 1s ease-in ;
}
</style>

也可以采用直接指定样式的方式

1
2
3
<transition enter-active-class="bounceIn" leave-active-class="bounceOut">
<div class="content animated" v-if="isShow"></div>
</transition>

示例

1
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
<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>Document</title>
<style >
.content{
width: 100px;height: 100px;background: red;;
}
.v-enter{ /*进入前*/
background: blue;;
}
.v-enter-active{
background: purple;
transition: all 10s linear;
}
.v-enter-to{
background: chartreuse;
}
/* 默认变成红色 */
.v-leave{
background: rgb(98, 0, 255);
}
.v-leave-active{
background: crimson;
transition: all 10s linear;
}
.v-leave-to{
background: yellow;
}
/*最终 消失 */
</style>
</head>
<body>
<!-- VUE 中的动画 v-if v-for v-show 路由切换 -->
<div id="app">
<button @click="change">点击我</button>
<transition> <!-- transition vue提供的添加动画标识-->
<div v-if="isShow" class="content">
content
</div>
</transition>
</div>
<script src="./node_modules/vue/dist/vue.js"></script>
<script>
let vm = new Vue({
el: "#app",
data:{
isShow: false,
},
methods:{
change(){
this.isShow = !this.isShow;
}
}
})
</script>
</body>

js编写动画

常用的钩子

  • before-enter 触发enter之前
  • before-leave 触发leave之前
  • enter 进入动画过程
  • leave 离开动画过程
  • after-enter 进入动画结束
  • after-leave 离开动画结束

示例

添加购物车的例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<div id="app">
<ul>
<li v-for="(list,index) in lists" ref="lists">
<img :src="list.cover">
<button @click="addCart(index)">加入购物车</button>
</li>
</ul>
<div class="cart" ref="cart">快进来!!!</div>
<!-- 实现动画 -->
<transition @enter="enter" @after-enter="after"> <!-- transition 创建动画元素 -->
<!-- span 进入写动画-->
<span class="animate" v-if="isShow"></span>
</transition>
</div>

我们可以借助 v-if来实现动画效果

1
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
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
ul li {
list-style: none;
display: flex;
align-items: center;
margin-bottom: 5px;
}
li img {
width: 150px;
height: 80px;
}
.cart {
position: fixed;
bottom: 0;
right: 0;
width: 150px;
height: 50px;
line-height: 50px;
text-align: center;
background: chartreuse;
}
.animate {
position: absolute;
width: 150px;
height: 80px;
display: block;
transition:all 1s linear ;
}
</style>
</head>

<body>
<div id="app">
<ul>
<li v-for="(list,index) in lists" ref="lists">
<img :src="list.cover">
<button @click="addCart(index)">加入购物车</button>
</li>
</ul>
<div class="cart" ref="cart">快进来!!!</div>
<!-- 实现动画 -->
<transition @enter="enter" @after-enter="after"> <!-- transition 创建动画元素 -->
<!-- span 进入写动画-->
<span class="animate" v-if="isShow"></span>
</transition>
</div>

<script src="node_modules/vue/dist/vue.js"></script>
<script>
let vm = new Vue({
el: '#app',
methods: {
enter(el,done){ // el:当前动画元素(即这里的span元素) done:动画完事了 需要调用done方法
// 如果将ref 添加到v-for 可以通过 this.$refs.lists = ['真实dom'];
let li = this.$refs.lists[this.currentIndex];
let {x,y} = li.getBoundingClientRect(); // js原生方法 获取坐标
el.style.left = x+'px';
el.style.top = y+'px';
el.style.background = `url(${this.lists[this.currentIndex].cover})`;
el.style.backgroundSize = `100% 100%`;
// 以上 将span元素放置到当前点击的元素上

let {x:a,y:b} = this.$refs.cart.getBoundingClientRect(); // 获取目的地坐标
// volicaty第三方库 纯js写
el.style.transform = `translate3d(${a-x}px,${b-y}px,0) scale(0,0)`;
// Vue 为了知道过渡的完成,必须设置相应的事件监听器。
el.addEventListener('transitionend',done);
},
after(){ // 结束后重置动画
this.isShow = false; // 直接隐藏
},
addCart(index){ // 加入购物车
this.currentIndex = index; // 点击谁就保存起来
this.isShow = true;
}
},
data() {
return {
isShow: false,
currentIndex:-1,
lists: [{
cover: 'http://www.javascriptpeixun.cn/files/course/2019/10-13/20510264fa40871768.png',
id: 1,
},
{
cover: 'http://www.javascriptpeixun.cn/files/course/2019/10-13/21114956089d654633.png',
id: 2,
},
{
cover: 'http://www.javascriptpeixun.cn/files/course/2019/10-13/2048331a9c5a183234.png',
id: 3,
}
]
}
}
})
</script>
</body>

4.3 多元素动画

如果动画遇到v-for就需要使用transition-group,而且每个元素必须增加key属性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<div class="nav-list" ref="box">
<transition-group>
<div class="nav-item" v-for="i in count" v-show="isShow" :key="i">{{i}}</div>
</transition-group>
</div>
<div class="nav" @click="show()">导航</div>
<script>
let vm = new Vue({
el: '#app',
methods:{ // 控制是否显示
show(){this.isShow = !this.isShow}
},
data() {
return {
isShow: false, count:6 // 循环六个导航
}
}
})
</script>
1
2
3
4
5
6
7
8
9
10
11
.nav-list .v-enter{ /*进入前的状态*/
opacity: 0;
transform: translate(0,0);
}
.v-enter-active,.v-leave-active{ /*运动中的效果*/
transition: all .5s linear;
}
.nav-list .v-leave-to{ /*离开后的目标*/
transform: translate(0,0);
opacity: 0;
}

六.面试题环节

  • computed和watch有什么区别?
  • Vue的生命周期,每个生命周期具体适合哪些场景
  • Vue中ref是什么?
  • Vue动画的生命周期?
  • Vue如何编写自定义指令?