过渡和动画基础
过渡和动画概述
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>示例效果: