前言
1
2
3
vue.js:634 [Vue warn]:
<transition> can only be used on a single element.
Use <transition-group> for lists.
注意: transition
标签下只能放单个元素, 多了只会显示第一个.
正文
Vue 中 CSS 动画原理
通过在特定时间点对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
<style>
/* 在动画的第一帧规定完全透明为 0 ,默认值为1 */
.v-enter {
opacity: 0;
}
/* 侦听不透明度的变化,如果有则在 2s 完成. 动画进入第二帧, v-enter 消失, opacity 变为默认值, 开始执行渐变效果 */
.v-enter-active{
transition: opacity 2s;
}
/* 规定在消失渐变第二帧非透明度为 0 */
.v-leave-to {
opacity: 0;
}
/* 当侦听到 opacity 发生变化, 动画随之改变 */
.v-leave-active {
transition: opacity 2s;
}
</style>
<div id="root">
<transition>
<p v-if="show">Hello World</p>
</transition>
<button @click="handleBtn()">切换</button>
</div>
使用 Animate.css 库制作动画
1.导入引用文件
1
<link href="https://cdn.bootcss.com/animate.css/3.7.2/animate.css" rel="stylesheet">
2.将 transition
标签进行改动
1
2
3
4
5
6
<transition
enter-active-class="animated zoomInLeft"
leave-active-class="animated hinge"
>
<p v-if="show">Hello World</p>
</transition>
给首次显示的元素添加动画
使用appear
属性:
1
2
3
4
5
6
<transition
appear
appear-active-class="animated zoomInLeft"
>
<p>AAA</p>
</transition>
将 过渡
与 Animate
结合
在 transition
标签添加 animated
属性的地方添加过渡类名.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<style>
.v-enter, .v-leave-to{
opacity: 0;
}
.v-enter-active, .v-leave-active {
transition: opacity 3s;
}
</style>
<transition
enter-active-class="animated shake v-enter-active"
leave-active-class="animated shake v-leave-active"
>
<p v-if="show">Hello World</p>
</transition>
但是这样会带来一个问题, Animate.css
动画持续时间为 1s , 但是我们设定的过渡动画时间为 3s , 这回造成当 animate
动画已经结束时, 过渡动画还没执行完的情况.
我们可以再 transition
标签中添加 type
属性来规定依据哪种动画的时间来执行.
1
2
3
4
5
6
7
<transition
type="transition"
enter-active-class="animated shake v-enter-active"
leave-active-class="animated shake v-leave-active"
>
<p v-if="show">Hello World</p>
</transition>
或者使用 :duration
属性来自定义时长.
1
2
3
4
5
6
7
<transition
:duration="4000"
enter-active-class="animated shake v-enter-active"
leave-active-class="animated shake v-leave-active"
>
<p v-if="show">Hello World</p>
</transition>
直到 4000ms
结束, 元素的类名才会发生变化.
1
2
3
4
5
6
7
<transition
:duration="{enter: 5000, leave: 5000}"
enter-active-class="animated shake v-enter-active"
leave-active-class="animated shake v-leave-active"
>
<p v-if="show">Hello World</p>
</transition>
这样可以更详细地控制时长.
JS 动画与 velocity.js
通过 Vue 给出的钩子, 我们可以通过 JS 实现简单动画.
入场:
- before-enter
- enter
- after-enter
出场:
- before-leave
- leave
- after-leave
我们在 transition
标签绑定事件, 然后在 methods
中实现.
1
2
3
4
5
6
7
<transition
@before-enter="handleBeforeEnter"
@enter="handleEnter"
@after-enter="handleAfterEnter"
>
<p v-if="show">Hello World</p>
</transition>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
methods: {
handleBeforeEnter (el) {
console.log('handleBeforeEnter');
el.style.color= "red";
},
handleEnter (el,done) {
setTimeout(() => {
el.style.color= 'green';
}, 1000);
setTimeout(() => {
done();
}, 2000);
},
handleAfterEnter (el) {
el.style.color= '#000';
}
}
velocity.js
是 JS 的一个动画库, 直接引用即可:
1
<script src="https://cdn.bootcss.com/velocity/2.0.5/velocity.js"></script>
使用方法与上面的 JS 动画一样, 只是在钩子方法中使用 Velocity 对象:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
methods: {
handleBeforeEnter (el) {
el.style.opacity = 0;
},
handleEnter (el,done) {
Velocity(el,{
opacity: 1
},{
duration: 1000,
// 注意: 动画结束要有 complete 属性
complete: done
})
},
handleAfterEnter (el) {
console.log('动画结束')
}
}
多元素或多组件的过渡
多元素过渡
与普通过渡使用方法一样用 transition
标签进行包裹, 区别是:
- 为每个元素设置一个
key
值, 放置 Vue 的元素复用 - 可以添加
mode
来规定动画的种类, 如:out-in
与in-out
多组件过渡
与普通过渡用法一样,可以通过 v-if
与 v-else
判断哪个元素显示, 也可以用动态组件 :is
+ 三元表达式
来判断显示哪一个组件.
列表过渡
与普通列表渲染无异, 在外层使用 transition-group
包裹, 在 style
中规定过渡样式.
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
<style>
.v-enter, .v-leave-to{
opacity: 0;
}
.v-enter-active, .v-leave-active{
transition: opacity 1s;
}
</style>
<div id="root">
<transition-group>
<div v-for="(item, index) in listA" :key="index">
{{item}}
</div>
</transition-group>
<button @click="handleClick">添加</button>
<button @click="handleDelete">删除</button>
</div>
<script>
var vm = new Vue({
el: '#root',
data() {
return {
listA: []
}
},
methods: {
handleClick () {
this.listA.push('hello world');
},
handleDelete () {
this.listA.pop();
}
}
})
</script>
对动画进行封装
使用 Vue.component
对动画进行封装.
1
2
3
4
5
6
Vue.component('fade',{
props: ['judege'],
template: `<transition>
<slot v-if="judege"></slot>
</transition>`
})
将 header
中的 style
保留, 或者可以使用 JS 动画, 参照上文在子组件 methods
中使用周期钩子即可.