一、过渡和动画的区别
- 过渡:通常用来表示元素上属性状态的变化。
- 动画:通常用来表示元素运动的情况。
二、使用Vue实现基础得css过渡与动画
1. 动画
/* css */ @keyframes leftToRight {0% {transform: translateX(-100px);}50% {transform: translateX(-50px);}100% {transform: translateX(0);} } .animation {animation: leftToRight 3s; }
// js const app = Vue.createApp({data() {return {animate: {animation: true}}},methods: {handleClick(){this.animate.animation = !this.animate.animation}},template: `<div :class='animate'>hello</div><button @click='handleClick'>切换</button>` });
2. 过渡
/* css */ .transition {transition: background-color 3s linear 0s; }.gold {background-color: gold; }.cyan {background-color: cyan; }
// js const app = Vue.createApp({data() {return {animate: {transition: true,gold: true,cyan: false}}},methods: {handleClick() {this.animate.gold = !this.animate.gold;this.animate.cyan = !this.animate.cyan;}},template: `<div :class='animate'>hello</div><button @click='handleClick'>切换</button>` });
- 以上是通过设置class属性实现的,同样通过设置style属性也可以实现:
/* css */ .transition {transition: background-color 3s linear 0s; }
// js data() {return {transition: 'transition',styleObject: {backgroundColor: 'gold'}} }, methods: {handleClick() {if(this.styleObject.backgroundColor === 'gold'){this.styleObject.backgroundColor = 'cyan';}else{this.styleObject.backgroundColor = 'gold';}} }, template: `<div :class='transition' :style='styleObject'>hello</div><button @click='handleClick'>切换</button> `
三、使用transition标签实现单元素/组件的过渡和动画效果
1. transition 的基本介绍
<transition>
元素作为单个元素/组件的过渡效果。<transition>
只会把过渡效果应用到其包裹的内容上,而不会额外渲染 DOM 元素,也不会出现在可被检查的组件层级中。
2. transition 的过渡class
在进入/离开的过渡中,会有 6 个 class 切换:
- v-enter-from:定义进入过渡的开始状态。在元素被插入之前生效,在元素被插入之后的下一帧移除。
- v-enter-active:定义进入过渡生效时的状态。在整个进入过渡的阶段中应用,在元素被插入之前生效,在过渡/动画完成之后移除。这个类可以被用来定义进入过渡的过程时间,延迟和曲线函数。
- v-enter-to:定义进入过渡的结束状态。在元素被插入之后下一帧生效 (与此同时 v-enter-from 被移除),在过渡/动画完成之后移除。
- v-leave-from:定义离开过渡的开始状态。在离开过渡被触发时立刻生效,下一帧被移除。
- v-leave-active:定义离开过渡生效时的状态。在整个离开过渡的阶段中应用,在离开过渡被触发时立刻生效,在过渡/动画完成之后移除。这个类可以被用来定义离开过渡的过程时间,延迟和曲线函数。
- v-leave-to:离开过渡的结束状态。在离开过渡被触发之后下一帧生效 (与此同时 v-leave-from 被删除),在过渡/动画完成之后移除。
3. 过渡示例
- 将需要过渡的元素使用transition标签包裹。
- 设置过渡需要的class,可从以上六种class中选择。
/* css */ /* .v-enter-from {opacity: 0; } .v-enter-active {transition: opacity 1s ease; } .v-enter-to {opacity: 1; } .v-leave-from {opacity: 1; } .v-leave-active {transition: opacity 1s ease; } .v-leave-to {opacity: 0; } */ /* 简写 */ .v-enter-from, .v-leave-to{opacity: 0; } .v-enter-active, .v-leave-active{transition: opacity 1s ease; }
// js const app = Vue.createApp({data() {return {show: true}},methods: {handleClick() {this.show = !this.show;}},template: `<transition><div v-if='show'>hello</div></transition><button @click='handleClick'>切换</button>` });
4. 动画示例
- 使用动画效果只需要修改css部分,js部分功能不变。
/* css */ @keyframes shake-in {0% {transform: translateX(-50px);}50% {transform: translateX(50px);}100% {transform: translateX(0px);} } @keyframes shake-out {0% {transform: translateX(50px);}50% {transform: translateX(-50px);}100% {transform: translateX(0px);} } .v-enter-active{animation: shake-in 1s ease-in; } .v-leave-active{animation: shake-out 1s ease-in-out; }
5. transition的name属性
name
-string
:用于自动生成 CSS 过渡类名,不写默认是v。- name设置为hy,对应的class名称也要改为hy开头。
// js <transition name='hy'><div v-if='show'>hello</div> </transition>
/* css */ .hy-enter-from, .hy-leave-to{opacity: 0; } .hy-enter-active, .hy-leave-active{transition: opacity 1s ease; }
6. 自定义过渡类名
我们可以通过以下 attribute 来自定义过渡类名:
enter-from-class
enter-active-class
enter-to-class
leave-from-class
leave-active-class
leave-to-class
他们的优先级高于普通的类名,这对于 Vue 的过渡系统和其他第三方 CSS 动画库,如 Animate.css. 结合使用十分有用。
// 首先引入样式文件 <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/4.1.1/animate.min.css" />const app = Vue.createApp({data() {return {show: true}},methods: {handleClick() {this.show = !this.show;}},// 以自定义过渡类名的方式去添加动画样式template: `<transition name='hy' enter-active-class='animate__animated animate__bounce'leave-active-class='animate__animated animate__bounce'><div v-if='show'>hello</div></transition><button @click='handleClick'>切换</button>` });
7. 同时设置过渡和动画
- 在一些场景中,你需要给同一个元素同时设置过渡和动画,比如 animation 很快的被触发并完成了,而 transition 效果还没结束。
- 在这种情况中,你就需要使用
type
attribute 并设置animation
或transition
来明确声明你需要 Vue 监听的类型。type - string。指定过渡事件类型,侦听过渡何时结束。有效值为 "transition" 和 "animation"。默认 Vue.js 将自动检测出持续时间长的为过渡事件类型。
在transition时间更长时,使用type=‘transiton’的效果:
- 可以发现animation先完成,但transition并没有终止会一致执行完,元素才消失。
/* css */ @keyframes shake-in {0% {transform: translateX(-50px);}50% {transform: translateX(50px);}100% {transform: translateX(0px);} }@keyframes shake-out {0% {transform: translateX(50px);}50% {transform: translateX(-50px);}100% {transform: translateX(0px);} }.v-enter-from, .v-leave-to {color: red; }.v-enter-active {animation: shake-in 1s ease-in;transition: color 3s ease-in; }.v-enter-to, .v-leave-from {color: green; }.v-leave-active {animation: shake-out 1s ease-in-out;transition: color 3s ease-in-out; }
// js const app = Vue.createApp({data() {return {show: true}},methods: {handleClick() {this.show = !this.show;}},template: `<transition type='transition'><div v-if='show'>hello</div></transition><button @click='handleClick'>切换</button>` });
在transition时间更长时,使用type=‘animation’的效果:
- 可以发现animation完成后,transition也会立即终止,元素也消失了。
<transition type='animation'><div v-if='show'>hello</div> </transition>
8. duration 属性
- duration - number | { enter: number, leave: number }:指定过渡的持续时间。
- 比css中设置的时间优先级更高。
- 单位是:ms。
<transition :duration='100' ><div v-if='show'>hello</div> </transition >
- 你也可以定制进入和移出的持续时间:
<transition :duration='{ enter: 1000, leave: 3000 }' ><div v-if='show'>hello</div> </transition >
9. 使用js实现动画
- 当只用 JavaScript 过渡的时候,在
enter
和leave
钩中必须使用done
进行回调。否则,它们将被同步调用,过渡会立即完成。- 添加
:css="false"
,也会让 Vue 会跳过 CSS 的检测,除了性能略高之外,这可以避免过渡过程中 CSS 规则的影响。想要用js实现动画,可以在transition的 attribute 中声明 JavaScript 钩子:
@before-enter="beforeEnter" 进入过渡前 @enter="enter" 进入过渡时 @after-enter="afterEnter" 进入过渡后 @enter-cancelled="enterCancelled" 进入过渡被打断时 @before-leave="beforeLeave" 离开过渡前 @leave="leave" 离开过渡时 @after-leave="afterLeave" 离开过渡后 @leave-cancelled="leaveCancelled" 离开过渡被打断时 const app = Vue.createApp({data() {return {show: true}},methods: {handleClick() {this.show = !this.show;},handleBeforeEnter(el){el.style.color = 'red';},handleEnter(el, done){const timer = setInterval(()=>{if(el.style.color === 'red'){el.style.color = 'blue';}else{el.style.color = 'red';}}, 1000);setTimeout(()=>{clearInterval(timer);// 动画结束标志// 不执行done()的话,handleAfterEnter不会执行done();}, 3000)},handleAfterEnter(el){console.log('success');;}},template: `<transition :css='false'@before-enter='handleBeforeEnter'@enter='handleEnter'@after-enter='handleAfterEnter'><div v-if='show'>hello</div></transition><button @click='handleClick'>切换</button>` });
四、组件和元素切换动画的实现
mode
-string
控制离开/进入过渡的时间序列。- 有效的模式有 先出后进:
"out-in"
和 先进后出:"in-out"
;默认同时进行。- 可以通过
appear
attribute 设置节点在初始渲染的过渡。/* css */ .v-enter-from, .v-leave-to {opacity: 0; }.v-enter-active, .v-leave-active {transition: opacity 1s ease-in; }.v-enter-to, .v-leave-from {opacity: 1; }
// js const app = Vue.createApp({components: ['item-a', 'item-b'],data() {return {component: 'item-a'}},methods: {handleClick() {if (this.component === 'item-a') {this.component = 'item-b';} else {this.component = 'item-a';}}},template: `<transition mode='out-in' appear><component :is='component' /></transition><button @click='handleClick'>切换</button>` }); app.component('item-a', {template: `<div>hello</div>` }); app.component('item-b', {template: `<div>bye</div>` });
五、列表动画
- 使用
<transition-group>
组件,可以同时渲染整个列表。- 内部元素总是需要提供唯一的
key
attribute 值。- CSS 过渡的类将会应用在内部的元素中,而不是这个组/容器本身。
<transition-group>
组件还有一个特殊之处。不仅可以进入和离开动画,还可以改变定位。要使用这个新功能只需使用新增的v-move
类。/* css */ .inline-block {display: inline-block;margin-right: 10px; }.v-enter-from, .v-leave-to {opacity: 0;transform: translateY(30px); }.v-enter-active {transition: all 1s ease; }.v-leave-active {position: absolute; }.v-move {transition: all 1s ease; }
// js const app = Vue.createApp({data() {return {list: [1, 2, 3]}},methods: {handleClick() {this.list.unshift(this.list.length + 1);},handleClickLeave(){this.list.shift();}},template: `<transition-group><div class='inline-block' v-for='item in list' :key='item'>{{item}}</div></transition-group><button @click='handleClick'>添加</button><button @click='handleClickLeave'>删除</button>` });
六、状态动画
- 对于数据元素本身而言,通过数字和运算、颜色的显示、SVG 节点的位置、元素的大小和其他的 property 这些属性的变化,同样可以实现动画的效果。
- 数字变化示例:
const app = Vue.createApp({data() {return {number: 1}},methods: {handleClick() {const timer = setInterval(() => {if (this.number >= 10) {clearInterval(timer)}else{this.number++;}}, 100);}},template: `<div>{{number}}</div><button @click='handleClick'>增加</button>` });
![]()