vue中css动画原理
# vue中css动画原理
[TOC]
# 一、过渡动画原理
.v-enter,
.v-leave-to {
opacity: 0;
}
.v-enter-active,
.v-leave-active {
transition: opacity 3s;
}
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
<div id="root">
<transition>
<div v-if="show">hello world</div>
</transition>
<button @click="handleBtnClick">change</button>
</div>
<script>
var vm = new Vue({
el: '#root',
data: {
show: true
},
methods: {
handleBtnClick: function() {
this.show = !this.show
}
}
})
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 二、在vue中使用animate.css库
# 2.1 无引入的写法
@keyframes bounce-in {
0% {
transform: scale(0);
}
50% {
transform: scale(1.5);
}
100% {
transform: scale(1);
}
}
.enter {
transform-origin: left center;
animation: bounce-in 3s;
}
.leave {
transform-origin: left center;
animation: bounce-in 3s reverse;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<div id="root">
<!-- <transition name="fade" enter-active-class="active" leave-active-class="leave"> -->
<transition enter-active-class="enter" leave-active-class="leave">
<div v-if="show">hello world</div>
</transition>
<button @click="handleBtnClick">change</button>
</div>
<script>
var vm = new Vue({
el: '#root',
data: {
show: true
},
methods: {
handleBtnClick: function() {
this.show = !this.show
}
}
})
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 2.2 引入的写法
<style></style>
<div id="root">
<transition enter-active-class="animate bounceIn" leave-active-class="animate bounceOut">
<div v-if="show">hello world</div>
</transition>
<button @click="handleBtnClick">change</button>
</div>
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
# 三、在vue中同时使用过渡和动画
- 初次显示也有动画
<div id="root">
<!-- appear使第一次显示也有动画 -->
<transition appear
enter-active-class="animate bounceIn"
leave-active-class="animate bounceOut"
appear-avtive-class="animate bounceIn">
<div v-if="show">hello world</div>
</transition>
<button @click="handleBtnClick">change</button>
</div>
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
- 同时过渡和动画并统一时长
.fade-enter,
.fade-leave-to {
opacity: 0;
}
.fade-enter-active,
.fade-leave-active {
transition: opacity 5s;
}
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
<div id="root">
<!-- 为了避免animate与transiton的动画时长不一致,需统一 -->
<!-- 第一种:type="transition" -->
<!-- 第二种::duration="10000" 默认单位:ms -->
<!-- 第三种 -->
<transition name="fade" :duration="{enter:10000,leave:5000}" appear enter-active-class="animate bounceIn fade-enter-active" leave-active-class="animate bounceOut fade-leave-active" appear-avtive-class="animate bounceIn">
<div v-if="show">hello world</div>
</transition>
<button @click="handleBtnClick">change</button>
</div>
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
# 四、vue中的js动画与velocity.js的结合
- js动画钩子
<div id="root">
<transition @before-enter="handleBeforeEnter"
@enter="handleEnter"
@after-enter="handleAfterEnter">
<div v-show="show">hello world</div>
</transition>
<button @click="handleBtnClick">toggle</button>
</div>
<script>
var vm = new Vue({
el: '#root',
data: {
show: true
},
methods: {
handleBtnClick: function() {
this.show = !this.show
},
//js动画钩子
//el指transition包裹的元素
handleBeforeEnter: function(el) {
el.style.color = 'red';
},
//done是回调函数
handleEnter: function(el, done) {
setTimeout(() => {
el.style.color = 'yellow'
}, 2000)
setTimeout(() => {
done()
}, 4000)
},
//由done()触发
handleAfterEnter: function(el) {
el.style.color = 'blue'
}
}
})
</script>
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
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
出场动画:把enter
换成leave
即可
- velocity.js
methods: {
handleBtnClick: function() {
this.show = !this.show
},
handleBeforeEnter: function(el) {
el.style.opacity = 0;
},
handleEnter: function(el, done) {
Velocity(el, {
opacity: 1
}, {
duration: 1000,
complete: done
})
},
handleAfterEnter: function(el) {
el.style.color = 'blue'
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 五、多个元素或组件的过渡
.v-enter,
.v-leave-to {
opacity: 0;
}
.v-enter-active,
.v-leave-active {
transition: opacity 1s;
}
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
# 5.1 多个元素的过渡动画
<div id="root">
<!-- mode控制切换模式,这里是先隐藏后显示 -->
<transition mode="out-in">
<!-- 添加key是为了避免div显示隐藏时出现dom复用 -->
<div v-if="show" key="hello">hello world</div>
<div v-else key="bye">bye world</div>
</transition>
<button @click="handleBtnClick">toggle</button>
</div>
<script>
var vm = new Vue({
el: '#root',
data: {
show: true
},
methods: {
handleBtnClick: function() {
this.show = !this.show
}
}
})
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 5.2 多个组件的过渡
<div id="root">
<transition mode="out-in">
<child-one v-if="show"></child-one>
<child-two v-else></child-two>
</transition>
<button @click="handleBtnClick">toggle</button>
</div>
<script>
Vue.component('child-one', {
template: '<div>child-one</div>'
})
Vue.component('child-two', {
template: '<div>child-two</div>'
})
var vm = new Vue({
el: '#root',
data: {
show: true
},
methods: {
handleBtnClick: function() {
this.show = !this.show
}
}
})
</script>
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
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
# 5.3 动态组件的过渡
<div id="root">
<transition mode="out-in">
<component :is="type"></component>
</transition>
<button @click="handleBtnClick">toggle</button>
</div>
<script>
Vue.component('child-one', {
template: '<div>child-one</div>'
})
Vue.component('child-two', {
template: '<div>child-two</div>'
})
var vm = new Vue({
el: '#root',
data: {
type: 'child-one'
},
methods: {
handleBtnClick: function() {
this.type = this.type === 'child-one' ? 'child-two' : 'child-one'
}
}
})
</script>
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
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
# 六、列表过渡
<div id="root">
<transition-group mode="out-in">
<!-- <transition-group> can only be used on a single element. Use <transition-group> for lists. -->
<!-- 不建议用index作为key值,一是会导致性能的降低,而是整个功能上可能会产生影响 -->
<!-- <div v-for="(item, index) of list" :key="index"></div> -->
<div v-for="item of list" :key="item.id">{{item.title}}</div>
</transition-group>
<button @click="handleBtnClick">add</button>
</div>
<script>
var count = 0;
var vm = new Vue({
el: '#root',
data: {
list: []
},
methods: {
handleBtnClick: function() {
this.list.push({
id: count++,
title: 'hello world'
})
}
}
})
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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
不带Key的复用情况是,
(1)当迭代的是数组的时候,是以数组的值作为唯一标识。
(2)当迭代的是个对象的话,就以对象的key作为标识。
当使用key属性来给每个节点做一个唯一标识,复用情况就不一样了,会复用已有的Dom节点元素,而Diff算法还可以正确的识别此新增的节点,并且能快速找到正确的位置区直接插入。
即key的主要作用是为了能高效的跟新虚拟DOM
# 七、动画封装
<div id="root">
<fade :show="show">
<div>hello world</div>
</fade>
<fade :show="show">
<div>bye world</div>
</fade>
<button @click="handleBtnClick">toggle</button>
</div>
<script>
Vue.component('fade', {
props: ['show'],
template: `
<transition @before-enter="handleBeforeEnter"
@enter="handleEnter"
@after-enter="handleAfterEnter">
<slot v-if="show"></slot>
</transition>
`,
methods: {
handleBeforeEnter: function(el) {
el.style.color = 'red'
},
handleEnter: function(el, done) {
setTimeout(() => {
el.style.color = 'yellow'
}, 2000)
setTimeout(() => {
done()
}, 4000)
},
handleAfterEnter: function(el) {
el.style.color = 'blue'
}
}
})
var vm = new Vue({
el: '#root',
data: {
show: true
},
methods: {
handleBtnClick: function() {
this.show = !this.show
}
}
})
</script>
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
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