动画分为两种:transition
和animation
,vue
只是将其融入组件中去使用了。css
v-if
、v-show
显示隐藏组件时添加动画transition
组件vue
内置组件,用以包裹想要实现动画效果的dom
节点,且只能包裹单个元素。html
如何实现包裹多个元素?——须要给transition
所包裹的子元素属性标签上添加v-if
、v-else
,须要注意的是:当transition
所包裹子元素的标签名相同时,须要给其添加上key
值,以避免影响dom
工做。vue
transition
实现原理给当前须要呈现变化的dom
元素添加上可能的6个class
样式:markdown
v-enter
v-enter-active
v-enter-to
过程:vue
自动帮咱们添加切换了样式,咱们只需设置好切换的类别便可。在dom
元素运动前一帧给其绑定一个class
属性v-enter
,随即消失。来到运动过程前一刻给其class
属性变为v-enter-active
和v-enter-to
,随着运动的进行,上述两个class
属性逐渐消失。app
name
属性:transition
标签头部可添加name
属性用以区分不一样动画。dom
<transition name="fade"></transition> <!-- vue就会将 .v-enter 变为 .fade-enter 用以私有化动画样式 --> 复制代码
appear
属性:动画一开始变展现出来。ide
<transition appear><transition> 复制代码
type
属性:存在transition
和animation
结合的动画,而且二者的动画时间存在长短的区别,咱们能够再transition
标签头部加上type
熟悉,用于告诉vue
咱们的动画是以哪一种方式的时间为基准的,避免上下窜动的不和谐效果,保持了两个动画的同步。函数
transition-group
列表过渡与transition
的区别:动画
transition-group
会生成一个真实的dom
节点,默认为span
,经过tag="ul"
可实现默认切换transition-group
必需要有key
值.v-enter, /* 时间点,开始动画以前元素的起始状态 */ .v-leave-to{ /* 时间点,元素完成动画离开的终止状态 */ opacity: 0; transform: translateX(70px) } .v-enter-active, /* 入场动画时间段 */ .v-leave-active{ /* 离场动画时间段 */ transition: all 0.8s ease; } .private-enter, .private-leave-to{ opacity: 0; transform: translateY(70px) } .private-enter-active, .private-leave-active{ transition: all 0.9s ease; } 复制代码
<div id="app"> <transition> <h1 v-show="flag1">使用过渡类名实现动画效果</h1> </transition> <br> <transition name="private"> <h1 v-show="flag2">demo</h1> </transition> <input type="button" value="按钮1" @click="flag1 = !flag1"> <input type="button" value="按钮2" @click="flag2 = !flag2"> </div> 复制代码
const app = new Vue({ el: '#app', data: { flag1: true, flag2: true } }) 复制代码
在使用第三方库(如:animate.css
)的时候,使用此方式比较多,常应用于退场动画中。this
animate.css
基于animation
来写的,其@keyframe
中已经设置了初始值和结束值,因此咱们只须要设置一下运动过程便可。譬以下面leave-active-class="animate shake"
中的属性值animate
是必须的,后面的shake
动画样式可去官网中寻找。
.a{ opacity: 0; } .b{ transition: opacity 10s; } .c{ opacity: 1; } 复制代码
<div id="app"> <transition enter-class="a" enter-active-class="b" enter-to-class="c" appear leave-active-class="animated shake"> <h1 v-show="flag">我要运动</h1> </transition> <button @click="flag = !flag">change</button> </div> 复制代码
const app = new Vue({ el: '#app', data: { flag: true } }) 复制代码
animate.css
的其余使用:
<div id="app"> <transition enter-active-class="bounceIn" leave-active-class="bounceOut"> <h3 v-if="flag">11111111111</h3> </transition> <input type="button" value="toggle1" @click="flag=!flag"> <!-- 设置入场和离场的动画时长 --> <transition enter-active-class="bounceIn" leave-active-class="bounceOut" :duration="1000"> <h3 v-if="flag1" class="animated">222222222222</h3> </transition> <input type="button" value="toggle2" @click="flag1=!flag1"> <!-- 分别设置入场和离场的动画时长 --> <transition enter-active-class="bounceIn" leave-active-class="bounceOut" :duration="{enter: 100,leave: 1000}"> <h3 v-if="flag2" class="animated">333333333333</h3> </transition> <input type="button" value="toggle3" @click="flag2=!flag2"> </div> 复制代码
js
钩子函数实现动画@before-enter
@enter
@after-enter
@enter-cancelled
@before-leave
@leave
@after-leave
@leave-cancelled
.fade-enter{ /* 定义进入过渡的开始状态,元素插入以前生效,元素插入的下一帧移除 */ opacity: 0; } .fade-enter-active{ /* 定义进入过渡生效时的动画状态 */ transition: opacity 1s; } .fade-enter-to{ /* 定义进入过渡的结束状态,过渡动画完成以后移除 */ opacity: 1; } .fade-leave{ opacity: 1; } .fade-leave-active{ transition: opacity 1s; } .fade-leave-to{ opacity: 0; } /* ------------分割线---------- */ .slide-enter{ opacity: 0; transform: translateY(20px); } .slide-enter-active{ transition: opacity 1s; /* transition和animation结合使用 */ animation: slide-in 1s ease-out; } .slide-enter-to{ opacity: 1; transform: translateY(0px); } .slide-leave{ opacity: 1; transform: translateY(0px); } .slide-leave-active{ transition: opacity 1s; animation: slide-out 1s ease-out; position: absolute; } .slide-leave-to{ opacity: 0; transform: translateY(20px); } .slide-mode{ transition: transform 1s; } @keyframes slide-in{ from{ transform: translateY(20px); } to{ transform: translateY(0px); } } @keyframes slide-out{ from{ transform: translateY(0px); } to{ transform: translateY(20px); } } /* ---------分割线------- */ .a{ opacity: 0; } .b{ transition: opacity 10s; } .c{ opacity: 1; } 复制代码
<div id="app"> <!-- 1 --> <button @click="show=!show">点击</button> <br> <select v-model="animatedName"> <option value="fade">闪现过渡动画</option> <option value="slide">上下滑动过渡动画</option> </select> <transition :name="animatedName"> <div v-show="show">我是属性绑定选择样式</div> </transition> <!-- 2 --> <br> <transition name="fade" appear> <div v-show="show">我是私有化提示语</div> </transition> <transition name="slide" appear> <div v-show="show">我是一句提示语</div> </transition> <!-- 3 --> <transition name="slide" appear mode="out-in"> <div v-if="show">sxw</div> <p v-else>iu</p> </transition> <!-- 4 --> <transition enter-class="a" enter-active-class="b" enter-to-class="c" appear> <div v-show="show">自定义样式标签</div> </transition> <!-- 5 --> <transition enter-active-class="animated bounce" leave-active-class="animated shake" appear> <div v-show="show">引用第三方库</div> </transition> </div> 复制代码
加强用户体验,以上栗子的两个注意点:
.slide-mode{ transition: transform 1s; } 复制代码
.slide-leave-active{ transition: opacity 1s; animation: slide-out 1s ease-out; position: absolute; /* 离开时候脱离文档流 */ } 复制代码
js
钩子函数实现动画<button @click="load = !load">js实现动画</button> <br> <transition @before-enter="beforeEnter" @enter="enter" @after-enter="afterEnter" @enter-cancelled="enterCancelled" @before-leave="beforeLeave" @leave="leave" @after-leave="afterLeave" @leave-cancelled="leaveCancelled" :css = "false"> <!-- 上一行代码告诉vue咱们不是使用css去实现动画的,减小了vue一开始去找css的步骤 --> <div v-if="load" style="width: 100px;height: 100px;background-color: red"></div> </transition> 复制代码
const vm = new Vue({ el: '#app', data: { load: false, divWidth: '' }, methods: { beforeEnter(el) { console.log(el) // <div v-if="load" style="width: 100px;height: 100px;background-color: red"></div> console.log("beforeEnter") this.divWidth = 10 // 限定每次初始动画时的div宽度 el.style.width = this.divWidth + 'px' }, enter(el, done) { console.log('enter') done(); // 这里须要执行一下done函数才能往下运行其余钩子函数 let round = 1; const timer = setInterval(() => { el.style.width = (this.divWidth + round * 10) + 'px' round ++ if(round > 20) { clearInterval(timer) done() } }, 20) }, afterEnter(el) { console.log('afterEnter') el.style.width = '300px' }, enterCancelled(el) { console.log('enterCancelled') }, beforeLeave(el) { console.log('beforeLeave') this.divWidth = '300' el.style.width = this.divWidth + 'px' }, leave(el, done) { console.log('leave') let round = 1 const timer = setInterval(() => { el.style.width = (this.divWidth - round * 10) + 'px' round ++ if(round > 20) { clearInterval(timer) done() } }, 20) }, afterLeave(el) { console.log('afterLeave') }, leaveCancelled(el) { console.log('leaveCancelled') } } }) 复制代码
js
钩子函数实现动画<div id="app"> <button @click="addClick">添加列表</button> <transition-group tag="ul" name="slide"> <li v-for="(list,index) in lists" @click="removeClick(index)" :key="list"> {{ list }} </li> </transition-group> </div> 复制代码
const vm = new Vue({ el: '#app', data: { list: [1,2,3] }, methods: { addClick() { const position = Math.floor(Math.random() * this.list.length) // 生成随机数 this.list.splice(position, 0, this.list.length + 1) // 添加的位置 删除的元素 添加元素个数 }, removeClick(index) { this.list.splice(index, 1) } } }) 复制代码
demo
- 小球加入购物车动画实现<div id="app"> <input type="button" value="加入购物车" @click="flag=!flag"> <transition @before-enter="beforeEnter" @enter="enter" @after-enter="afterEnter"> <div class="ball" v-show="flag" style="width: 15px;height: 15px;background-color: red;border-radius: 50%;"></div> </transition> </div> 复制代码
const app = new Vue({ el: '#app', data: { flag: false }, methods: { // el表示要执行动画的dom元素 beforeEnter(el) { // 动画入场前,设置元素开始动画的起始位置 el.style.transform = 'translate(0, 0)' }, enter(el, done) { // 设置小球完成动画以后的结束状态 el.offsetWidth // 强制刷新动画 el.style.transform = 'translate(150px, 450px)' el.style.transition = 'all 1s ease' // 执行done函数,完成下面钩子函数 done() }, afterEnter(el) { // 动画完成以后调用afterEnter函数 // 控制小球的显示与隐藏,直接跳事后半场动画,让flag标识符变为false this.flag = !this.flag el.style.opacity = 0.5 } } }) 复制代码
demo
- 列表动画 - 添加删除功能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-move和v-leave-active结合使用,使得列表的过渡动画更加平缓柔和! */ .v-move{ transition: all 0.8s ease; } .v-leave-active{ position: absolute; } 复制代码
<div id="app"> <div> <label for=""> Id: <input type="text" v-model="id"> </label> <label for=""> Name: <input type="text" v-model="name"> </label> <input type="button" value="添加" @click="add"> </div> <ul> <!-- 列表过渡,若是须要过渡的元素是经过v-for循环渲染出来的,就不能使用transition包裹,应该使用transitionGroup --> <!-- 若要为v-for循环建立的元素设置动画,必须为每一个元素绑定key值 --> <!-- appear属性实现页面展现时的入场动画 --> <transition-group appear tag="ul"> <li v-for="(item,index) in list" :key="item + index" @click="del(index)"> {{item.id}} -- {{item.name}} </li> </transition-group> </ul> </div> 复制代码
const vm = new Vue({ el: '#app', data: { id: '', name: '', list: [ { id: 1, name: 'a' }, { id: 2, name: 'b' }, { id: 3, name: 'c' } ] }, methods: { add() { this.list.push( {id: this.id,name: this.name }) this.id = this.name = '' }, del(index) { this.list.splice(index, 1) } } }) 复制代码