10-Vue动画

前言

动画的作用:提高用户的体验,帮助用户更好的理解页面中的功能。

使用过渡类名实现动画

官方文档的截图

过渡类名如下:

动画进入:

  • v-enter:动画进入之前的初始状态

  • v-enter-to:动画进入之后的结束状态

  • v-enter-active:动画进入的时间段

PS:第一、第二个是时间点;第三个是时间段。

动画离开:

  • v-leave:动画离开之前的初始状态

  • v-leave-to:动画离开之后的结束状态

  • v-leave-active:动画离开的时间段

PS:第一、第二个是时间点;第三个是时间段。

使用举例(通过Vue的过渡类名来实现)

v-enter-to和v-leave的状态是一样的。而且一般来说,v-enter和v-leave-to的状态也是一致的。所以,我们可以把这四个状态写成两组。

现在我们来做个例子:点击按钮时,让div显示/隐藏。

1、引入

如果我们不使用动画,应该是这样做:

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
<!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>Document</title>

<script src="vue2.5.16.js"></script>

</head>

<body>

<div id="app">

<input type="button" value="toggle" @click="flag=!flag">

<!-- 需求: 点击按钮,让 h3 显示,再点击,让 h3 隐藏 -->

<h3 v-if="flag">这是一个H3</h3>

</div>

<script>

// 创建 Vue 实例,得到 ViewModel

var vm = new Vue({

el: '#app',

data: {

flag: false

},

methods: {}

});

</script>

</body>

</html>

2、使用动画:(通过Vue的过渡类名来实现)

现在,我们加淡入淡出的动画,让div显示和隐藏。代码如下:

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
<!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>Document</title>

<script src="vue2.5.16.js"></script>

<!-- 2. 自定义两组样式,来控制 transition 内部的元素实现动画 -->

<style>

/* v-enter 【这是一个时间点】
是进入之前,元素的起始状态,此时还没有开始进入 */

/* v-leave-to 【这是一个时间点】
是动画离开之后,离开的终止状态,此时,元素 动画已经结束了 */

.v-enter,

.v-leave-to {

opacity: 0;

}

/* v-enter-active 【入场动画的时间段】 */

/* v-leave-active 【离场动画的时间段】 */

.v-enter-active,

.v-leave-active {

transition: all 1s ease;
/*期间,设置过渡的属性:all表示所有的属性、时间为1秒、过渡的状态*/

}

</style>

</head>

<body>

<div id="app">

<input type="button" value="toggle" @click="flag=!flag">

<!-- 需求: 点击按钮,让 h3 显示,再点击,让 h3 隐藏 -->

<!-- 1. 使用 transition 元素,把 需要被动画控制的元素,包裹起来 -->

<!-- transition 元素,是 Vue 官方提供的 -->

<transition>

<h3 v-if="flag">这是一个H3</h3>

</transition>

</div>

<script>

// 创建 Vue 实例,得到 ViewModel

var vm = new Vue({

el: '#app',

data: {

flag: false

},

methods: {}

});

</script>

</body>

</html>

上方代码中,我们使用vue提供的标签把需要被动画控制的元素,包裹起来;然后使用.v-enter、.v-leave-to等进行动画的定义。

运行效果如下:

3、再加一个 transform 属性进行位移

我们在上方代码的基础之上,加一个 transform
属性,让动画有一个位移的效果。完整代码如下:

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
<!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>Document</title>

<script src="vue2.5.16.js"></script>

<!-- 2. 自定义两组样式,来控制 transition 内部的元素实现动画 -->

<style>

/* v-enter 【这是一个时间点】
是进入之前,元素的起始状态,此时还没有开始进入 */

/* v-leave-to 【这是一个时间点】
是动画离开之后,离开的终止状态,此时,元素 动画已经结束了 */

.v-enter,

.v-leave-to {

opacity: 0;

/* 在动画中加入位移 */

transform: translateX(80px); /*
smyhvae提示:v-enter表示,一开始让DOM元素处于靠右80px的位置 */

}

/* v-enter-active 【入场动画的时间段】 */

/* v-leave-active 【离场动画的时间段】 */

.v-enter-active,

.v-leave-active {

transition: all 1s ease;
/*期间,设置过渡的属性:all表示所有的属性、时间为1秒、过渡的状态*/

}

</style>

</head>

<body>

<div id="app">

<input type="button" value="toggle" @click="flag=!flag">

<!-- 需求: 点击按钮,让 h3 显示,再点击,让 h3 隐藏 -->

<!-- 1. 使用 transition 元素,把 需要被动画控制的元素,包裹起来 -->

<!-- transition 元素,是 Vue 官方提供的 -->

<transition>

<h3 v-if="flag">这是一个H3</h3>

</transition>

</div>

<script>

// 创建 Vue 实例,得到 ViewModel

var vm = new Vue({

el: '#app',

data: {

flag: false

},

methods: {}

});

</script>

</body>

</html>

效果如下:

修改过渡类名的前缀

在上一小段中,.v-enter、.v-leave-to这些过渡类名都是以v-开头的。这样做,会有一个局限性:假设有两个DOM元素都用进行了包裹,那这两个DOM元素就都具备了v-中所定义的动画。

如果我们想把两个DOM元素的动画进行分开定义,该怎么做呢?这里,我们可以通过修改过渡类名的前缀来做。比如:

第一步:(自定义别名)

1
2
3
4
5
<transition name="my">

<h6 v-if="flag2">这是一个H6</h6>

</transition>

上方代码中,我们加了name=”my”。

第二步:(我们就可以使用 my-enter、.my-leave-to这些类名了)

1
2
3
4
5
6
7
8
9
.my-enter,

.my-leave-to {

opacity: 0;

transform: translateY(70px);

}

完整代码举例如下;

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
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
131
132
133
134
135
136
137
138
139
<!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>Document</title>

<script src="./lib/vue-2.4.0.js"></script>

<style>

/* 自定义第一组样式,来控制 transition 内部的元素实现动画 */

/* v-enter 【这是一个时间点】
是进入之前,元素的起始状态,此时还没有开始进入 */

/* v-leave-to 【这是一个时间点】
是动画离开之后,离开的终止状态,此时,元素 动画已经结束了 */

.v-enter,

.v-leave-to {

opacity: 0;

transform: translateX(150px);

}

/* v-enter-active 【入场动画的时间段】 */

/* v-leave-active 【离场动画的时间段】 */

.v-enter-active,

.v-leave-active {

transition: all 0.8s ease;

}

/* 自定义第二组样式,来控制 transition
内部的元素实现动画。这次,我们通过自己起的别名`name`来作为指令 */

.my-enter,

.my-leave-to {

opacity: 0;

transform: translateY(70px);

}

.my-enter-active,

.my-leave-active {

transition: all 1s ease;

}

</style>

</head>

<body>

<div id="app">

<!-- 第一组 -->

<input type="button" value="toggle" @click="flag=!flag">

<!-- 使用 transition 元素,把 需要被动画控制的元素 h3,包裹起来 -->

<!-- transition 元素,是 Vue 官方提供的 -->

<transition>

<h3 v-if="flag">这是一个H3</h3>

</transition>

<hr>

<!-- 第二组 -->

<input type="button" value="toggle2" @click="flag2=!flag2">

<!-- 使用 transition 元素,把 需要被动画控制的元素 h6,包裹起来 -->

<!-- transition 元素,是 Vue 官方提供的 -->

<!--
【重点】在这里,我们给这个transition定义一个别名,叫`name`,然后,我们就可以通过
`.my-enter`等 来定义动画的样式【重要】 -->

<transition name="my">

<h6 v-if="flag2">这是一个H6</h6>

</transition>

</div>

<script>

// 创建 Vue 实例,得到 ViewModel

var vm = new Vue({

el: '#app',

data: {

flag: false,

flag2: false

},

methods: {}

});

</script>

</body>

</html>

运行效果如下:

使用第三方animate.css类库实现动画

animate.css网址:

代码举例

下面的代码中,我们使用animate.css提供的bounceIn、bounceOut这两个类来做入场、离场的动画。代码如下:

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
<!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>Document</title>

<script src="vue2.5.16.js"></script>

<link rel="stylesheet" href="animate3.6.0.css">

<!-- 入场 bounceIn 离场 bounceOut -->

</head>

<body>

<div id="app">

<input type="button" value="toggle" @click="flag=!flag">

<!-- 需求: 点击按钮,让 h3 显示,再点击,让 h3 隐藏 -->

<transition enter-active-class=" animate__animated
animate__bounceIn" leave-active-class=" animate__animated
animate__bounceOut">

<h3 v-if="flag">这是一个H3</h3>

</transition>

</div>

<script>

// 创建 Vue 实例,得到 ViewModel

var vm = new Vue({

el: '#app',

data: {

flag: false

},

methods: {}

});

</script>

</body>

</html>

上面的代码中,注意:

注意1:enter-active-class和leave-active-class这两个类名是Vue动画里的关键词,不能写成自己随意起的类名。

注意2:bounceIn、bounceOut这两个类不能直接使用,要在前面加上animated这个类;否则动画是不会生效的。当然,上面的代码中,我们还可以把class
= animated这个代码移到

标签里,效果是一样的,如下:

1
2
3
4
5
6
7
8
<!-- 需求: 点击按钮,让 h3 显示,再点击,让 h3 隐藏 -->

<transition enter-active-class="bounceIn"
leave-active-class="bounceOut">

<h3 v-if="flag" class="animate__animated">这是一个H3</h3>

</transition>

运行效果如下:

改进1:(统一设置入场、出场动画的持续时间)

我们把上面的代码改进一下,如果我们想给入场、出场动画设置持续的时间,可以使用:duration来做。如下:

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
<!-- 需求: 点击按钮,让 h3 显示,再点击,让 h3 隐藏 -->

<!-- 使用 :duration="毫秒值" 来统一设置 入场 和 离场 时候的动画时长
-->

<transition enter-active-class="animate__animated
animate__bounceIn" leave-active-class=" animate__animated
animate__bounceOut" :duration="500">

<h3 v-if="flag">这是一个H3</h3>

</transition>

**改进2**:(分别设置入场、出场动画的持续时间)

<!-- 需求: 点击按钮,让 h3 显示,再点击,让 h3 隐藏 -->

<!-- 使用 :duration="{ enter: 1000, leave: 300 }" 来分别设置
入场的时长 和 离场的时长 -->

<transition enter-active-class=" animate__animated
animate__bounceIn" leave-active-class=" animate__animated
animate__bounceOut" :duration="{ enter: 1000, leave: 300 }">

<h3 v-if="flag">这是一个H3</h3>

</transition>

钩子函数实现半场动画

只有出场动画、没有离场动画,这种就是属于半场动画。比如你把一件商品加入收藏,会出现一个动画;当再次点击收藏按钮的时候却看不到动画效果,这就说明,只有前一半才有动画。

半场动画,可以使用钩子函数来实现。

动画的钩子函数介绍

可以在属性中声明 JavaScript
钩子函数:(这八个钩子函数可以理解成是动画的生命周期)

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
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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
<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"

>

<!-- DOM元素 -->

</transition>

我们可以这样理解:上面这八个钩子函数(四个入场、四个离场),对应了八个事件,我们要紧接着在methods中定义八个函数。

如果要定义半场动画,做法是:直接在methods中写入场动画的函数,不写离场动画的函数即可。

**举例:使用钩子函数模拟小球半场动画**

现在要实现的例子是:点击按钮后,让小球进行移动。完整代码如下:

<!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>Document</title>

<script src="vue2.5.16.js"></script>

<style>

.ball {

width: 15px;

height: 15px;

border-radius: 50%;

background-color: red;

}

</style>

</head>

<body>

<div id="app">

<input type="button" value="加入购物车" @click="flag=!flag">

<!-- 1. 使用 transition 元素把 小球包裹起来 -->

<transition @before-enter="beforeEnter" @enter="enter"
@after-enter="afterEnter">

<div class="ball" v-show="flag"></div>

</transition>

</div>

<script>

var vm = new Vue({

el: '#app',

data: {

flag: false

},

methods: {

// 注意: 动画钩子函数的第一个参数:el,表示
要执行动画的那个DOM元素,是个原生的 JS DOM对象

// 我们可以认为 , el 是通过 document.getElementById('')
方式获取到的原生JS DOM对象

beforeEnter(el) {

// beforeEnter 表示动画入场之前,此时,动画尚未开始,可以 在 beforeEnter
中,设置元素开始动画之前的起始样式

// 设置小球开始动画之前的 起始位置

el.style.transform = "translate(0, 0)" //
smyhvae提示:一开始的时候,让小球处于(00)的位置

},

enter(el, done) {

// 【注意1】el.offsetWidth
这句话,没有实际的作用,但是,如果不写,出不来动画效果。可以认为
el.offsetWidth 会强制动画刷新

el.offsetWidth

// enter 表示动画
开始之后的样式,这里,可以设置小球完成动画之后的,结束状态

el.style.transform = "translate(150px, 300px)" // smyhvae
提示:让小球从(00)移动到 (150px, 300px)

el.style.transition = 'all 1s ease'

// 【注意2】这里的 done, 起始就是 afterEnter 这个函数,也就是说:done
是 afterEnter 函数的引用

done()

},

afterEnter(el) {

// 动画完成之后,会调用 afterEnter

// console.log('ok')

// 动画结束后,让小球消失(直接让 flag 取反即可)

this.flag = !this.flag //
因为最开始的时候,小球就是处于消失的状态,这行代码可以让小球的动画重新开始

}

}

});

</script>

</body>

</html>

运行效果如下:(我们可以用这种动画效果,做类似于”加入购物车”的动画效果)

上面的代码中,有两个地方要注意:

注意1

el.offsetWidth这行代码不能少。虽然这行代码没有实际的意义,但是少了之后,动画效果出不来:

当然,我们也可以把这行代码换成el.offsetHeight、el.offsetLeft、el.offsetTop之类的,只要包含了offset就行。

注意2

enter()函数里,函数的第二个参数要加上done,函数体的最后一行要写done(),表示立即执行后面的afterEnter()函数;如果没有这个done,则会延迟执行后面的afterEnter()函数:

Vue官方文档的解释是这样:

当只用 JavaScript
过渡的时候,在enter和leave中必须使用done进行回调。否则,它们将被同步调用,过渡会立即完成。

使用transition-group元素实现列表动画

现在的场景是:在一个

    列表中,如果我想给指定的某个li添加动画效果,该怎么做呢?(需要声明的是,这些li是用v-for循环进行遍历的)

    如果我们用把li包裹起来,就会让所有的li都具备了动画,这显然是不可取的。

    那该怎么做呢?这里我们就可以用transition-group进行包裹。

    代码举例1:点击添加按钮后,给新增的 item 加个动画

    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
    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
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241
    242
    243
    244
    245
    246
    247
    248
    249
    250
    251
    252
    253
    254
    255
    256
    257
    258
    259
    260
    261
    262
    263
    264
    265
    266
    267
    268
    269
    270
    271
    272
    273
    274
    275
    276
    277
    278
    279
    280
    281
    282
    283
    284
    285
    286
    287
    288
    289
    290
    291
    292
    293
    294
    295
    296
    297
    298
    299
    300
    301
    302
    303
    304
    305
    306
    307
    308
    309
    310
    311
    312
    313
    314
    315
    316
    317
    318
    319
    320
    321
    322
    323
    324
    325
    326
    327
    328
    329
    330
    331
    332
    333
    334
    335
    336
    337
    338
    339
    340
    341
    342
    343
    344
    345
    346
    347
    348
    349
    350
    351
    352
    353
    354
    355
    356
    357
    358
    359
    360
    361
    362
    363
    364
    365
    366
    367
    368
    369
    370
    371
    372
    373
    374
    375
    376
    377
    378
    379
    380
    381
    382
    383
    384
    385
    386
    387
    388
    389
    390
    391
    392
    393
    394
    395
    396
    397
    398
    399
    400
    401
    402
    403
    404
    405
    406
    407
    408
    409
    410
    411
    412
    413
    414
    415
    416
    417
    418
    419
    420
    421
    422
    423
    424
    425
    426
    427
    428
    429
    430
    431
    432
    433
    434
    435
    436
    437
    438
    439
    440
    441
    442
    443
    444
    445
    446
    447
    448
    449
    450
    451
    452
    453
    454
    455
    456
    457
    458
    459
    460
    461
    462
    463
    464
    465
    466
    467
    468
    469
    470
    471
    472
    473
    474
    475
    476
    477
    478
    479
    480
    481
    482
    483
    484
    485
    486
    487
    488
    489
    490
    491
    492
    493
    494
    495
    496
    497
    498
    499
    500
    501
    502
    503
    504
    505
    506
    507
    508
    509
    510
    511
    512
    513
    514
    515
    516
    517
    518
    519
    520
    521
    522
    523
    524
    525
    526
    527
    528
    529
    530
    531
    532
    533
    534
    535
    536
    537
    538
    539
    540
    541
    542
    543
    544
    545
    546
    547
    548
    549
    550
    551
    552
    553
    554
    555
    556
    557
    558
    559
    560
    561
    562
    563
    564
    565
    566
    567
    568
    569
    570
    571
    572
    573
    574
    575
    576
    577
    578
    579
    580
    581
    582
    583
    584
    585
    586
    587
    588
    589
    590
    591
    592
    593
    594
    595
    596
    597
    598
    599
    600
    601
    602
    603
    604
    605
    606
    607
    608
    609
    610
    611
    612
    613
    614
    615
    616
    617
    618
    619
    620
    621
    622
    623
    624
    625
    626
    627
    628
    629
    630
    631
    632
    633
    634
    635
    636
    637
    638
    639
    640
    641
    642
    643
    644
    645
    646
    647
    648
    649
    650
    651
    652
    653
    654
    655
    656
    657
    658
    659
    660
    661
    662
    663
    664
    665
    666
    667
    668
    669
    670
    671
    672
    673
    674
    675
    676
    677
    678
    679
    680
    681
    682
    683
    684
    685
    686
    687
    688
    689
    690
    691
    692
    693
    694
    695
    696
    697
    698
    699
    700
    701
    702
    703
    704
    705
    706
    707
    708
    709
    710
    711
    712
    713
    714
    715
    716
    717
    718
    719
    720
    721
    722
    723
    724
    725
    726
    727
    728
    729
    730
    <!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>Document</title>

    <script src="vue2.5.16.js"></script>

    <style>

    li {

    border: 1px dashed #999;

    margin: 5px;

    line-height: 35px;

    padding-left: 5px;

    font-size: 12px;

    width: 100%;

    }

    li:hover {

    background-color: hotpink;

    transition: all 0.8s ease;
    /*鼠标悬停时,出现背景色。让这个背景色的出现,也加一个淡入的动画*/

    }

    .v-enter,

    .v-leave-to {

    opacity: 0;

    transform: translateY(80px);

    }

    .v-enter-active,

    .v-leave-active {

    transition: all 0.6s ease;

    }

    </style>

    </head>

    <body>

    <div id="app">

    <div>

    <label>

    Id:

    <input type="text" v-model="id">

    </label>

    <label>

    Name:

    <input type="text" v-model="name">

    </label>

    <input type="button" value="添加" @click="add">

    </div>

    <!-- <ul> -->

    <!-- 在实现列表过渡的时候,如果需要过渡的元素,是通过 v-for
    循环渲染出来的,不能使用 transition 包裹,需要使用 transitionGroup -->

    <!-- 如果要为 v-for 循环创建的元素设置动画,必须为每一个 元素 设置
    :key 属性 -->

    <transition-group>

    <li v-for="(item, i) in list" :key="item.id">

    {{item.id}} --- {{item.name}}

    </li>

    </transition-group>

    <!-- </ul> -->

    </div>

    <script>

    // 创建 Vue 实例,得到 ViewModel

    var vm = new Vue({

    el: '#app',

    data: {

    id: '',

    name: '',

    list: [

    { id: 1, name: '赵高' },

    { id: 2, name: '秦桧' },

    { id: 3, name: '严嵩' },

    { id: 4, name: '魏忠贤' }

    ]

    },

    methods: {

    add() {

    this.list.push({ id: this.id, name: this.name })

    this.id = this.name = ''

    }

    }

    });

    </script>

    </body>

    </html>

    运行效果如下:

    ![](/img/5ef9c9d1c7bccbbb52e21378e9564fe7747ef490.gif)


    **改进1**:添加删除item的功能

    基于上面的代码,我们来添加**删除item**的功能,代码本应该是这样写:

    <!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>Document</title>

    <script src="vue2.5.16.js"></script>

    <style>

    li {

    border: 1px dashed #999;

    margin: 5px;

    line-height: 35px;

    padding-left: 5px;

    font-size: 12px;

    width: 100%;

    }

    li:hover {

    background-color: hotpink;

    transition: all 0.8s ease;

    /*鼠标悬停时,出现背景色。让这个背景色的出现,也加一个淡入的动画*/

    }

    .v-enter,

    .v-leave-to {

    opacity: 0;

    transform: translateY(80px);

    }

    .v-enter-active,

    .v-leave-active {

    transition: all 0.6s ease;

    }

    </style>

    </head>

    <body>

    <div id="app">

    <div>

    <label>

    Id:

    <input type="text" v-model="id">

    </label>

    <label>

    Name:

    <input type="text" v-model="name">

    </label>

    <input type="button" value="添加" @click="add">

    </div>

    <!-- <ul> -->

    <!-- 在实现列表过渡的时候,如果需要过渡的元素,是通过 v-for
    循环渲染出来的,不能使用 transition 包裹,需要使用 transitionGroup -->

    <!-- 如果要为 v-for 循环创建的元素设置动画,必须为每一个 元素 设置
    :key 属性 -->

    <transition-group>

    <li v-for="(item, i) in list" :key="item.id" @click="del(i)">

    {{item.id}} --- {{item.name}}

    </li>

    </transition-group>

    <!-- </ul> -->

    </div>

    <script>

    // 创建 Vue 实例,得到 ViewModel

    var vm = new Vue({

    el: '#app',

    data: {

    id: '',

    name: '',

    list: [

    { id: 1, name: '赵高' },

    { id: 2, name: '秦桧' },

    { id: 3, name: '严嵩' },

    { id: 4, name: '魏忠贤' }

    ]

    },

    methods: {

    add() {

    this.list.push({ id: this.id, name: this.name })

    this.id = this.name = ''

    },

    del(i) {

    this.list.splice(i, 1);

    }

    }

    });

    </script>

    </body>

    </html>

    运行效果如下:

    ![](/img/04e212edc0e07db1a8bb38716a0b1f6de2c642f2.gif)


    **改进2:**:

    上图中,我们发现,当我删除第2个item时,**第3、第4个item在往上移动的过程比会较突兀**。为了改进这个地方,我们可以给.v-move、.v-leave-active加一些动画属性。最终,完整版代码如下:

    <!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>Document</title>

    <script src="vue2.5.16.js"></script>

    <style>

    li {

    border: 1px dashed #999;

    margin: 5px;

    line-height: 35px;

    padding-left: 5px;

    font-size: 12px;

    width: 100%;

    }

    li:hover {

    background-color: hotpink;

    transition: all 0.8s ease;

    /*鼠标悬停时,出现背景色。让这个背景色的出现,也加一个淡入的动画*/

    }

    .v-enter,

    .v-leave-to {

    opacity: 0;

    transform: translateY(80px);

    }

    .v-enter-active,

    .v-leave-active {

    transition: all 0.6s ease;

    }

    /* 下面的 .v-move 和 .v-leave-active
    配合使用,能够实现列表后续的元素,渐渐地漂上来的效果 */

    .v-move {

    transition: all 0.6s ease;

    }

    .v-leave-active {

    position: absolute;

    }

    </style>

    </head>

    <body>

    <div id="app">

    <div>

    <label>

    Id:

    <input type="text" v-model="id">

    </label>

    <label>

    Name:

    <input type="text" v-model="name">

    </label>

    <input type="button" value="添加" @click="add">

    </div>

    <!-- <ul> -->

    <!-- 在实现列表过渡的时候,如果需要过渡的元素,是通过 v-for
    循环渲染出来的,不能使用 transition 包裹,需要使用 transitionGroup -->

    <!-- 如果要为 v-for 循环创建的元素设置动画,必须为每一个 元素 设置
    :key 属性 -->

    <transition-group>

    <li v-for="(item, i) in list" :key="item.id" @click="del(i)">

    {{item.id}} --- {{item.name}}

    </li>

    </transition-group>

    <!-- </ul> -->

    </div>

    <script>

    // 创建 Vue 实例,得到 ViewModel

    var vm = new Vue({

    el: '#app',

    data: {

    id: '',

    name: '',

    list: [

    { id: 1, name: '赵高' },

    { id: 2, name: '秦桧' },

    { id: 3, name: '严嵩' },

    { id: 4, name: '魏忠贤' }

    ]

    },

    methods: {

    add() {

    this.list.push({ id: this.id, name: this.name })

    this.id = this.name = ''

    },

    del(i) {

    this.list.splice(i, 1);

    }

    }

    });

    </script>

    </body>

    </html>

    运行效果如下:

    ![](/img/49c9976bd3e451b58fec5fffccc77c912ad3d7cf.gif)


    **transition-group中appear和tag属性的作用**

    我们可以在上面的代码基础之上,给transition-group加上appear属性,这样的话,可以让transition-group包裹的所有DOM元素在刷新时,有**淡入效果**。

    <!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>Document</title>

    <script src="vue2.5.16.js"></script>

    <style>

    li {

    border: 1px dashed #999;

    margin: 5px;

    line-height: 35px;

    padding-left: 5px;

    font-size: 12px;

    width: 100%;

    }

    li:hover {

    background-color: hotpink;

    transition: all 0.8s ease;

    }

    .v-enter,

    .v-leave-to {

    opacity: 0;

    transform: translateY(80px);

    }

    .v-enter-active,

    .v-leave-active {

    transition: all 0.6s ease;

    }

    /* 下面的 .v-move 和 .v-leave-active
    配合使用,能够实现列表后续的元素,渐渐地漂上来的效果 */

    .v-move {

    transition: all 0.6s ease;

    }

    .v-leave-active {

    position: absolute;

    }

    </style>

    </head>

    <body>

    <div id="app">

    <div>

    <label>

    Id:

    <input type="text" v-model="id">

    </label>

    <label>

    Name:

    <input type="text" v-model="name">

    </label>

    <input type="button" value="添加" @click="add">

    </div>

    <ul>

    <!-- 在实现列表过渡的时候,如果需要过渡的元素,是通过 v-for
    循环渲染出来的,不能使用 transition 包裹,需要使用 transitionGroup -->

    <!-- 如果要为 v-for 循环创建的元素设置动画,必须为每一个 元素 设置
    :key 属性 -->

    <!-- 给 ransition-group 添加 appear
    属性,实现页面刚展示出来时候,入场时候的效果 -->

    <!-- 通过 为 transition-group 元素,设置 tag 属性,指定
    transition-group 渲染为指定的元素,如果不指定 tag 属性,默认,渲染为
    span 标签 -->

    <transition-group appear>

    <li v-for="(item, i) in list" :key="item.id" @click="del(i)">

    {{item.id}} --- {{item.name}}

    </li>

    </transition-group>

    </ul>

    </div>

    <script>

    // 创建 Vue 实例,得到 ViewModel

    var vm = new Vue({

    el: '#app',

    data: {

    id: '',

    name: '',

    list: [

    { id: 1, name: '赵高' },

    { id: 2, name: '秦桧' },

    { id: 3, name: '严嵩' },

    { id: 4, name: '魏忠贤' }

    ]

    },

    methods: {

    add() {

    this.list.push({ id: this.id, name: this.name })

    this.id = this.name = ''

    },

    del(i) {

    this.list.splice(i, 1)

    }

    }

    });

    </script>

    </body>

    </html>

    改进:transition-group的tag属性

    上面的代码中,我们审查一下代码元素会发现,用transition-group包裹的元素,会被默认套上一层

    这个虽然没有太大副作用,但是不符合代码规范。为了解决这个问题,我们可以通过tag属性给transition-group包谷的元素套上一层

      ,然后把现有的
        注释掉,就可以了。最终代码如下:

        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
        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
        131
        132
        133
        134
        135
        136
        137
        138
        139
        140
        141
        142
        143
        144
        145
        146
        147
        148
        149
        150
        151
        152
        153
        154
        155
        156
        157
        158
        159
        160
        161
        162
        163
        164
        165
        166
        167
        168
        169
        170
        171
        172
        173
        174
        175
        176
        177
        178
        179
        180
        181
        182
        183
        184
        185
        186
        187
        188
        <!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>Document</title>

        <script src="vue2.5.16.js"></script>

        <style>

        li {

        border: 1px dashed #999;

        margin: 5px;

        line-height: 35px;

        padding-left: 5px;

        font-size: 12px;

        width: 100%;

        }

        li:hover {

        background-color: hotpink;

        transition: all 0.8s ease;

        }

        .v-enter,

        .v-leave-to {

        opacity: 0;

        transform: translateY(80px);

        }

        .v-enter-active,

        .v-leave-active {

        transition: all 0.6s ease;

        }

        /* 下面的 .v-move 和 .v-leave-active
        配合使用,能够实现列表后续的元素,渐渐地漂上来的效果 */

        .v-move {

        transition: all 0.6s ease;

        }

        .v-leave-active {

        position: absolute;

        }

        </style>

        </head>

        <body>

        <div id="app">

        <div>

        <label>

        Id:

        <input type="text" v-model="id">

        </label>

        <label>

        Name:

        <input type="text" v-model="name">

        </label>

        <input type="button" value="添加" @click="add">

        </div>

        <!-- <ul> -->

        <!-- 在实现列表过渡的时候,如果需要过渡的元素,是通过 v-for
        循环渲染出来的,不能使用 transition 包裹,需要使用 transitionGroup -->

        <!-- 如果要为 v-for 循环创建的元素设置动画,必须为每一个 元素 设置
        :key 属性 -->

        <!-- 给 ransition-group 添加 appear
        属性,实现页面刚展示出来时候,入场时候的效果 -->

        <!-- 通过 为 transition-group 元素,设置 tag 属性,指定
        transition-group 渲染为指定的元素,如果不指定 tag 属性,默认,渲染为
        span 标签 -->

        <transition-group appear tag="ul">

        <li v-for="(item, i) in list" :key="item.id" @click="del(i)">

        {{item.id}} --- {{item.name}}

        </li>

        </transition-group>

        <!-- </ul> -->

        </div>

        <script>

        // 创建 Vue 实例,得到 ViewModel

        var vm = new Vue({

        el: '#app',

        data: {

        id: '',

        name: '',

        list: [

        { id: 1, name: '赵高' },

        { id: 2, name: '秦桧' },

        { id: 3, name: '严嵩' },

        { id: 4, name: '魏忠贤' }

        ]

        },

        methods: {

        add() {

        this.list.push({ id: this.id, name: this.name })

        this.id = this.name = ''

        },

        del(i) {

        this.list.splice(i, 1)

        }

        }

        });

        </script>

        </body>

        </html>

        这样的话,审查元素的效果如下:


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!