1. Vue 中的动画
Vue
在插入、更新或者移除 DOM
时,提供多种不同方式的应用过渡效果。
包括以下工具:
- 使用过渡类名:使用
transition
元素包裹要设置动画的元素 - 第三方 CSS 动画库:
animate.css
- 在过渡钩子函数中使用
JavaScript
直接操作DOM
- 列表排序过渡:
transition-group
1.1 单元素过渡
Vue 提供了 transition 的封装组件,在下列情形中,可以给任何元素和组件添加进入/离开过渡
- 条件渲染 (使用 v-if)
- 条件展示 (使用 v-show)
- 动态组件
- 组件根节点
1.1.1 过渡类名
在进入/离开的过渡中,会有 6 个 class 切换。
- v-enter:定义进入过渡的开始状态。在元素被插入之前生效,在元素被插入之后的下一帧移除。
- v-enter-active:定义进入过渡生效时的状态。在整个进入过渡的阶段中应用,在元素被插入之前生效,在过渡/动画完成之后移除。这个类可以被用来定义进入过渡的过程时间,延迟和曲线函数。
- v-enter-to: 2.1.8版及以上 定义进入过渡的结束状态。在元素被插入之后下一帧生效 (与此同时 v-enter 被移除),在过渡/动画完成之后移除。
- v-leave: 定义离开过渡的开始状态。在离开过渡被触发时立刻生效,下一帧被移除。
- v-leave-active:定义离开过渡生效时的状态。在整个离开过渡的阶段中应用,在离开过渡被触发时立刻生效,在过渡/动画完成之后移除。这个类可以被用来定义离开过渡的过程时间,延迟和曲线函数。
- v-leave-to: 2.1.8版及以上 定义离开过渡的结束状态。在离开过渡被触发之后下一帧生效 (与此同时 v-leave 被删除),在过渡/动画完成之后移除。
示例:
给 h3
元素设置进入退出动画:
<style>
/* 自定义两组样式,来控制 transition 内部的元素实现动画 */
/* v-enter 时间点,元素进入之前的其实状态,此时还未正式进入 */
/* v-leave-to 时间点,动画离开之后,离开的终止状态,此时,元素动画已结束 */
.v-enter,
.v-levae-to {
opacity: 0; /*透明度*/
transform: translateX(150px); /*元素从 150px 处飘过来,x 轴*/
}
/* v-enter-active 入场动画的时间段 */
/* v-levave-active 离场动画的时间段 */
.v-enter-active,
.v-levae-activue {
transition: all 0.8s ease;
}
</style>
<body>
<div id="app">
<input type="button" value="按钮" @click="flag=!flag">
<transition>
<h3 v-if="flag">标题三</h3>
</transition>
</div>
<script src="./lib/vue-2.4.0.js"></script>
<script>
var vm = new Vue({
el: ‘#app‘,
data: {
flag: false
},
methods: {}
})
</script>
</body>
1.1.2 修改过渡类名前缀给多个元素设置动画
若有多个元素需要设置不同的动画,如果使用同一种过渡类名,那么动画将是一致的,这时就需要修改过渡类名的前缀 + transition
的 name
属性来实现。
<style>
/* 自定义 v 前缀 */
.my-enter,
.my-leave-to {
opacity: 0;
transform: translateY(70px); /*从上飞入*/
}
.my-enter-active,
.my-leave-active {
transition: all 0.8s ease;
}
</style>
<body>
<div id="app">
<input type="button" value="按钮" @click="flag=!flag">
<transition>
<h3 v-if="flag">标题三</h3>
</transition>
<input type="button" value="按钮2" @click="flag2=!flag2">
<transition name="my">
<h1 v-if="flag2">标题一</h3>
</transition>
</div>
<script src="./lib/vue-2.4.0.js"></script>
<script>
var vm = new Vue({
el: ‘#app‘,
data: {
flag: false,
flag2: false
},
methods: {}
})
</script>
</body>
1.2 第三方 CSS 动画库 animate
1、导入动画类库:
<link rel="stylesheet" type="text/css" href="./lib/animate.css">
2、定义 transition
及属性:
<transition
enter-active-class="fadeInRight"
leave-active-class="fadeOutRight"
:duration="{ enter: 500, leave: 800 }">
<div class="animated" v-show="isshow">动画哦</div>
</transition>
示例:
<!DOCTYPE html>
<html lang="">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Title Page</title>
<link rel="stylesheet" href="./lib/animate.css">
</head>
<body>
<div id="app">
<input type="button" value="按钮" @click="flag=!flag">
<!-- 需求: 点击按钮,让 h3 显示,再点击,让 h3 隐藏 -->
<!-- <transition enter-active-class="animated bounceIn" leave-active-class="animated bounceOut">
<h3 v-if="flag">这是一个H3</h3>
</transition> -->
<!-- 使用 :duration="毫秒值" 来统一设置 入场 和 离场 时候的动画时长 -->
<!-- <transition enter-active-class="bounceIn" leave-active-class="bounceOut" :duration="200">
<h3 v-if="flag" class="animated">这是一个H3</h3>
</transition> -->
<!-- 使用 :duration="{ enter: 200, leave: 400 }" 来分别设置 入场的时长 和 离场的时长 -->
<transition enter-active-class="bounceIn" leave-active-class="bounceOut" :duration="{ enter: 200, leave: 400 }">
<h3 v-if="flag" class="animated">标题三</h3>
</transition>
</div>
<script src="./lib/vue-2.4.0.js"></script>
<script>
var vm = new Vue({
el: ‘#app‘,
data: {
flag: false,
},
methods: {}
})
</script>
</body>
</html>
参考文档:
1.3 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>
JS 中调用:
// ...
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) {
// ...
}
}
示例:
利用 JavaScript 钩子函数实现小球半场动画,模拟加入购物车场景:
<!DOCTYPE html>
<html lang="">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Title Page</title>
<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">
<!-- 使用 transition 元素将小球包裹起来 -->
<transition
@before-enter="beforeEnter"
@enter="enter"
@after-enter="afterEnter">
<div class="ball" v-show="flag"></div>
</transition>
</div>
<script src="./lib/vue-2.4.0.js"></script>
<script>
var vm = new Vue({
el: ‘#app‘,
data: {
flag: false,
},
methods: {
beforeEnter(el) {
// 动画入场之前,动画尚未开始,用于设置元素开始动画之前的起始样式
// 设置小球开始动画之前的起始位置
el.style.transform = "translate(0, 0)" // 起始坐标
},
enter(el, done) {
el.offsetWidth // el.offsetWidth 会强制动画刷新
// 动画开始之后的样式,设置小球动画之后的,结束状态
el.style.transform = "translate(150px, 450px)" // 结束坐标
el.style.transition = "all 1s ease"
done() // 起始就是 afterEnter 这个函数,也就是说:done 是 afterEnter 函数的引用
},
afterEnter(el) {
// 动画完成后,隐藏小球,flag 初始值为 false,点击按钮后为 true,!flag 即为 false
this.flag = !this.flag
}
}
})
</script>
</body>
</html>
Tips:当只用 JavaScript 过渡的时候,在 enter 和 leave 中必须使用 done 进行回调。否则,它们将被同步调用,过渡会立即完成。
参考文章:
1.4 列表过渡
目前为止,关于过渡动画我们已经了解了:
- 单个节点
- 同一时间渲染多个节点中的一个
若要渲染整个列表,使用 <transition-group>
组件,组件特点:
-
<transition-group>
会模块渲染为一个<span>
标签,若想渲染为其他标签,可以使用tag
属性更换,如:tag="ul"
- 内部元素需要提供唯一的
key
属性值 -
CSS
过渡类将会应用在内部元素中,而不是这个组/容器本身
示例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<link rel="stylesheet" href="./lib/bootstrap-3.3.7.css">
<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 class="col-md-8">
<div>
<label>
Id:
<input type="text" v-model="id">
</label>
<label>
Name:
<input type="text" v-model="name" @keyup.enter="add">
</label>
<input type="button" value="添加" @click="add">
</div>
<!-- 使用 transition-group 包裹要过渡的列表 -->
<!-- v-for 循环创建元素,设置动画,且必须为每一个元素设置 :key 属性 -->
<!-- appear 属性,实现页面展示时,入场时的结果 -->
<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>
</div>
</div>
<script src="./lib/vue-2.4.0.js"></script>
<script>
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>
参考文章: