Vue.js 前端开发实战之 05-Vue 过渡和动画
过渡和动画基础
过渡和动画概述
Vue 在插入、更新或者移除 DOM 时,提供了多种过渡效果。
过渡,就是从一个状态向另外一个状态插入值,新的状态替换了旧的状态。
Vue 提供了内置的过渡封装组件 transition,可以结合 CSS 动画 @keyframes 实现动画效果。
transition 组件
Vue 提供了内置的过渡封装组件,即 transition 组件。
transition 组件的基本用法:
<!-- 过渡类名前缀:替换过渡类的v-前缀 -->
<transition name="过渡类名前缀">
<!-- 需要添加过渡的元素 -->
<!-- 组件在同一时间内只能有一个元素显示 -->
<div></div>
</transition>Vue 为 transition 标签内部的元素提供了 3 个进入过渡的类和 3 个离开过渡的类。
transition 组件的基本过渡类:
| 过渡状态 | 过渡类型 | 描述 |
|---|---|---|
| 进入(enter) | v-enter | 进入过渡的开始状态,作用于开始的一帧 |
| v-enter-active | 进入过渡生效时的状态,作用于整个过程 | |
| v-enter-to | 进入过渡的结束状态,作用于结束的一帧 | |
| 离开(leave) | v-leave | 离开过渡的开始状态,作用于开始的一帧 |
| v-leave-active | 离开过渡生效时的状态,作用于整个过程 | |
| v-leave-to | 离开过渡的结束状态,作用于结束的一帧 |
示例:transition 组件
入口页面(index.html):
<style>
/** 图形的初始状态 **/
.box {
width: 200px;
height: 50px;
background-color: blue;
}
/** 进入和离开的过程 **/
.box-enter-active, .box-leave-active {
transition: width 3s;
}
/** 进入的初始状态和离开的结束状态 **/
.box-enter, .box-leave-to {
width: 0px;
}
/** 进入的结束状态和离开的初始状态 **/
.box-enter-to, .box-leave {
width: 200px;
}
</style>
<div id="app">
<button @click="toggle">显示/隐藏</button><br><br>
<transition name="box">
<div class="box" v-if="show"></div>
</transition>
</div>
<script>
let vm = new Vue({
el: '#app',
data: {
show: true
},
methods: {
toggle() {
this.show = !this.show
}
}
})
</script>示例效果:
自定义类名
transition 组件提供了一系列自定义类名属性,允许使用自定义的类名,且自定义类名的优先级高于普通类名,与第三方库结合实现更精美的过渡效果。
自定义类名的基本用法:
<transition 自定义类名属性="类名">
<div></div>
</transition>transition 组件的基本自定义类名属性:
| 过渡状态 | 过渡类型 | 描述 |
|---|---|---|
| 进入(enter) | enter-class | 同 v-enter |
| enter-active-class | 同 v-enter-active | |
| enter-to-class | 同 v-enter-to | |
| 离开(leave) | leave-class | 同 v-leave |
| leave-active-class | 同 v-leave-active | |
| leave-to-class | 同 v-leave-to |
结合 animate.css 实现过渡效果
animate.css 是一个跨浏览器的 CSS3 动画库,其内置了很多经典的 CSS3 动画,通过 transition 组件的自定义类名和 animate.css 动画库结合,可以实现精美的过渡效果。
animate.css 文档:https://www.animate.style/
示例:结合 animate.css 实现过渡效果
入口页面(index.html):
<link rel="stylesheet" href="animate.css">
<div id="app">
<button @click="toggle">显示/隐藏</button><br><br>
<transition enter-active-class="animate__animated animate__backInDown"
leave-active-class="animate__animated animate__backOutDown">
<div class="box" v-if="show"></div>
</transition>
</div>示例效果:
使用 appear 初始渲染过渡效果
过渡效果都是在事件处理方法中控制的,在元素初始渲染时,并不会触发过渡效果。
appear 属性用于设置元素初始渲染时,给元素添加过渡效果。
appear 属性的基本用法:
<transition appear appear属性="值">
<div></div>
</transition>transition 组件的基本 appear 属性:
| 名称 | 描述 |
|---|---|
| appear-class | 初始时的 class 样式 |
| appear-active-class | 应用在整个过渡过程中的 class 样式 |
| appear-to-class | 过渡完成的 class 样式 |
示例:使用 appear 初始渲染过渡效果
入口页面(index.html):
<transition
appear
appear-active-class="animate__animated animate__swing"
enter-active-class="animate__animated animate__backInDown"
leave-active-class="animate__animated animate__backOutDown">
<div class="box" v-if="show"></div>
</transition>示例效果:
使用 @keyframes 实现动画
@keyframes 用于声明关键帧创建动画。
@keyframes 规则创建动画,就是将一套 CSS 样式逐步演变成另一套样式,在创建动画过程中,可以多次改变 CSS 样式。
@keyframes 的基本用法:
@keyframes 动画名称 {
from {
/* 开始时,即0%时的CSS样式 */
}
xx% {
/* xx%时的CSS样式 */
}
to {
/* 结束时,即100%时的CSS样式 */
}
}示例:使用 @keyframes 实现动画
入口页面(index.html):
<style>
.circle {
width: 100px;
height: 100px;
background-color: red;
border-radius: 50%;
}
@keyframes ami {
0% {
transform: scale(0);
background-color: red;
}
20% {
transform: scale(1);
background-color: burlywood;
}
50% {
transform: scale(1.5);
background-color: blueviolet;
}
100% {
transform: scale(1);
background-color: burlywood;
}
}
/** 进入过程 **/
.bounce-enter-active {
animation: ami 5s;
}
/** 离开过程 **/
.bounce-leave-active {
animation: ami 5s;
}
</style>
<div id="app">
<button @click="toggle">显示/隐藏</button>
<br><br>
<transition name="bounce">
<div class="circle" v-if="show"></div>
</transition>
</div>
<script>
let vm = new Vue({
el: '#app',
data: {
show: false
},
methods: {
toggle() {
this.show = !this.show
}
}
})
</script>示例效果:
使用钩子函数实现动画
Vue 中除了使用 CSS 动画外,还可以借助 JavaScript 来完成动画,transition 组件中定义了一些动画钩子函数,用来实现动画。
钩子函数的基本用法:
<transition @钩子函数="触发方法">
<div></div>
</transition>
<script>
let vm = new Vue({
el: '#app',
methods: {
// beforeEnter等触发方法时,可以传入参数el
// el:transition包裹的元素
beforeEnter(el) {
// ...
},
// enter和leave触发方法时,可以传入参数done
enter(el, done) {
// ...
// 调用done()告诉Vue动画结束
done()
}
}
})
</script>transition 组件的基本钩子函数:
| 名称 | 描述 |
|---|---|
| before-enter | 入场前 |
| enter | 入场时 |
| after-enter | 入场后 |
| enter-cancelled | 取消入场时 |
| before-leave | 出场前 |
| leave | 出场时 |
| after-leave | 出场后 |
| leave-cancelled | 取消出场 |
示例:使用钩子函数实现动画
入口页面(index.html):
<div id="app">
<button @click="toggle">显示/隐藏</button><br><br>
<transition @enter="enter" @leave="leave">
<div class="box" v-if="show"></div>
</transition>
</div>
<script>
let vm = new Vue({
el: '#app',
data: {
show: true
},
methods: {
toggle() {
this.show = !this.show
},
enter(el, done) {
el.style.width = '200px'
done()
},
leave(el, done) {
el.style.width = '0px'
done()
}
}
})
</script>示例效果:
结合 Velocity.js 实现动画
Velocity.js 是一个简单易用、高性能且功能丰富的轻量级 JavaScript 动画库,其拥有颜色动画、转换动画、循环、缓动、SVG 动画和滚动动画等特色功能,通过 transition 组件的钩子函数和 Velocity.js 动画库结合,可以实现精美的动画效果。
Velocity.js 文档:http://www.velocityjs.org/
示例:结合 Velocity.js 实现动画
入口页面(index.html):
<script src="1.5.0/velocity.js"></script>
<div id="app">
<button @click="toggle">显示/隐藏</button><br><br>
<transition @enter="enter">
<div class="box" v-if="show"></div>
</transition>
</div>
<script>
let vm = new Vue({
el: '#app',
data: {
show: true
},
methods: {
toggle() {
this.show = !this.show
},
enter(el, done) {
Velocity(el, "fadeIn", { duration: 1500 })
done()
}
}
})
</script>示例效果:
多个元素过渡
不同标签名元素的过渡
不相同标签名元素可以使用 v-if 和 v-else 来进行过渡。
示例:不同标签名元素的过渡
入口页面(index.html):
<style>
.fade-enter-active, .fade-leave-active {
transition: opacity 3s;
}
.fade-enter, .fade-leave-to {
opacity: 0;
}
.fade-enter-to, .fade-leave {
opacity: 1;
}
</style>
<div id="app">
<button @click="toggle">切换登录/注册页面</button>
<br>
<transition name="fade">
<h1 v-if="isLogin">登录页面</h1>
<h2 v-else>注册页面</h2>
</transition>
</div>
<script>
let vm = new Vue({
el: '#app',
data: {
isLogin: true
},
methods: {
toggle() {
this.isLogin = !this.isLogin
}
}
})
</script>示例效果:
相同标签名元素的过渡
当有相同标签名的元素切换时,需要通过 key 特性设置唯一值来标记,从而让 Vue 区分它们。如果没有为元素设置 key,Vue 为了效率只会替换相同标签中的内容。
示例:相同标签名元素的过渡
入口页面(index.html):
<style>
.fade-enter-active, .fade-leave-active {
transition: opacity 3s;
}
.fade-enter, .fade-leave-to {
opacity: 0;
}
.fade-enter-to, .fade-leave {
opacity: 1;
}
</style>
<div id="app">
<button @click="toggle">切换登录/注册按钮</button>
<br><br>
<transition name="fade">
<button v-if="isLogin" key="login">登录按钮</button>
<button v-else key="register">注册按钮</button>
</transition>
</div>
<script>
let vm = new Vue({
el: '#app',
data: {
isLogin: true
},
methods: {
toggle() {
this.isLogin = !this.isLogin
}
}
})
</script>示例效果:
过渡模式
新旧两个元素参与过渡的时候,新元素的进入和旧元素的离开会同时触发,这是因为 transition 组件的默认行为进入和离开同时发生了。
如果要求离开的元素完全消失后,进入的元素再显示出来,可以使用 transition 提供的过渡模式属性,来解决当一个元素离开后,另一个元素进来时发生的位置的闪动或阻塞问题。
过渡模式的基本用法:
<transition mode="过渡模式">
<div></div>
</transition>transition 组件的基本过渡模式:
| 名称 | 描述 |
|---|---|
| in-out(默认) | 新元素先进行过渡进入,完成之后当前元素过渡离开 |
| out-in | 当前元素先进行过渡离开,完成之后新元素过渡进入 |
示例:过渡模式
入口页面(index.html):
<transition name="fade" mode="out-in">
<button v-if="isLogin" key="login">登录按钮</button>
<button v-else key="register">注册按钮</button>
</transition>示例效果:
多个组件过渡
多个组件之间的过渡,不需要使用 key 特性,只需要使用动态组件即可。
动态组件需要通过 Vue 中的 component 元素绑定 is 属性来实现多组件的过渡。
多个组件过渡的基本用法:
<transition>
<component :is="组件名称"></component>
</transition>示例:多个组件过渡
入口页面(index.html):
<style>
.fade-enter-active, .fade-leave-active {
transition: opacity 3s;
}
.fade-enter, .fade-leave-to {
opacity: 0;
}
.fade-enter-to, .fade-leave {
opacity: 1;
}
</style>
<div id="app">
<button @click="compontentName='login'">登录</button>
<button @click="compontentName='register'">注册</button>
<br><br>
<transition name="fade" mode="out-in">
<component :is="compontentName"></component>
</transition>
</div>
<template id="login">
<span>我是登录组件</span>
</template>
<template id="register">
<span>我是注册组件</span>
</template>
<script>
Vue.component('login', {
template: '#login'
})
Vue.component('register', {
template: '#register'
})
let vm = new Vue({
el: '#app',
data: {
compontentName: ''
}
})
</script>示例效果:
列表过渡
列表过渡需要使用 v-for 和 transition-group 组件来实现。
- 列表的每一项都需要进行过渡,列表在循环时要给每一个列表项添加唯一的 key 属性。
- 在进行列表过渡时 , 过渡模式不可用。
列表过渡的基本用法:
<!--
<transition-group>:相当于给每一个被包裹的li元素在外面添加了<transition>
tag:渲染的外层标签
-->
<transition-group name="list" tag="ul">
<li v-for="item in items" :key="item">
{{item}}
</li>
</transition-group>示例:列表过渡
入口页面(index.html):
<style>
.list-enter-active, .list-leave-active {
transition: all 2s;
}
.list-enter, .list-leave-to {
opacity: 0;
}
.list-enter-to, .list-leave {
opacity: 1;
}
</style>
<div id="app">
<button @click="add">随机插入一个数字</button>
<button @click="remove">随机移除一个数字</button>
<transition-group name="list" tag="ul">
<li v-for="item in items" :key="item">
{{item}}
</li>
</transition-group>
</div>
<script>
let vm = new Vue({
el: '#app',
data: {
items: [1, 2, 3, 4, 5],
nextNum: 6
},
methods: {
add () {
this.items.push(this.nextNum++)
},
remove () {
this.items.splice(-1, 1)
}
}
})
</script>示例效果: