一、Vue控制动画的几种方法
1. css的transition
2. css的animation
3. js操作动画
二、单元素/组件的过渡
在讲Vue的动画前,先了解一下动画在vue中的存在时间
<div id="demo">
<button v-on:click="show = !show">
Toggle
</button>
<transition name="fade">
<p v-if="show">hello</p>
</transition>
</div>
new Vue({
el: '#demo',
data: {
show: true
}
})
.fade-enter-active, .fade-leave-active {
transition: opacity .5s;
}
.fade-enter, .fade-leave-to {
opacity: 0;
}
代码逻辑:
Vue 在插入、更新或者移除 DOM 时,提供多种不同方式的应用过渡效果。
transition 组件中的DOM元素,在下列情形中,根据css类添加进入/离开过渡动画
- 条件渲染 (使用 v-if)
- 条件展示 (使用 v-show)
- 动态组件
- 组件根节点
三、过渡的类名(动画的生命周期)
在进入/离开的过渡中,会有 6 个 class 切换,分时间段添加到DOM元素上。
对于这些在过渡中切换的类名来说,如果你使用一个没有名字的 <transition>,则 v- 是这些类名的默认前缀。如果你使用了 <transition name="my-transition">,那么 v-enter 会替换为 my-transition-enter。
v-enter-active和v-leave-active两个类可以在前面定义,过程时间,延迟和曲线函数。
v-enter表示dom元素进入动画第一帧的状态,之后变化到v-enter-to时的状态,再到dom元素正常时候的状态,接着到v-leave时的状态,再到v-leave-to时的状态,之后dom元素消失。
.fade-enter { width: 100px; background: red;}
.fade-enter-to { width: 200px; background: red;}
p { background: red; width: 500px;}
.fade-leave { width: 200px;
background: red;
}
.fade-leave-to { background: red; width: 100px;}
.fade-enter-active { transition: all 3s;}
.fade-leave-active { transition: all 3s;}
p元素出现的状态演示:
100px => 200px => 500px //0直接变成100px,200px直接变成500px
p元素消失时的状态演示:
500px => 200px => 100px //最后100px直接消失
一般不加v-enter-to和v-leave类,因为两个都应该是dom元素原本的模样
四、6个class的添加顺序
要理解动画的本质,就是把样式的改变加上时间
1. 先给dom元素加上v-enter和v-enter-active //初始样式
2. 下一帧去掉v-enter,加上v-enter-to //变化后的样式
3. 过渡结束删掉v-enter-to和v-enter-active
4. 现在只剩下dom元素本身的样式
5. 加上v-leave和v-leave-active //由于动画本质是样式的改变,所以
6. 下一帧去掉v-leave加上v-leave-to //可以理解为dom原本的样式=>v-leave-t
7. 过渡结束删掉v-leave-to和v-leave-active //o的样式
v-leave只存在一帧具体动画可以自己推断,如果原本的dom元素存在样式,一般直接忽略v-leave的样式,直接原本样式=>v-leave-to的样式,因为时间太短
五、Vue的animation用法
Vue的animation是依然使用transition来控制dom的动画效果
动画尽量写在active上,因为它全程都在
.bounce-enter-active {
animation: bounce-in .5s;
}
.bounce-leave-active {
animation: bounce-in .5s reverse;
}
@keyframes bounce-in {
0% {
transform: scale(0);
}
50% {
transform: scale(1.5);
}
100% {
transform: scale(1);
}
}
最后的100%尽量变成原来的模样,因为动画结束100%后,仍然需要恢复原来的模样,而此时v-enter-active类已经去掉了,所以会很快地从100%的样式变到原本样式。同理消失时也一样
我们可以使用第三方动画库来使用animation,不用写@语句了(animate.css)
enter-class
enter-active-class
enter-to-class
(2.1.8+)leave-class
leave-active-class
leave-to-class
(2.1.8+)
来使用库
<transition
name="custom-classes-transition"
enter-active-class="animated tada"
leave-active-class="animated bounceOutRight"
>
动画有两种实现方式:在transition上或者在css类上
transition上的优先级高于普通的类名,这对于 Vue 的过渡系统和其他第三方 CSS 动画库,如 Animate.css结合使用十分有用。
通常呢,animation是写在v-active类上的,因为active类始终存在
六、过渡和动画的区别
过渡就是从一个状态向另一个状态插入值。很简单。从起始状态,到结束状态
动画有点不同,你可以在一个声明中设置多个状态。比如,你可以在动画 50% 的位置设置一个关键帧,然后在 70% 的位置设置一个完全不同的状态
动画也可以实现过渡的功能,只需要从头到尾插入状态,但是过渡无法像动画一样插入多个值。
七、动画的js钩子
<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的钩子,之后要在method里面定义函数
enter: function (el, done) {
// ...
done()
},
当只用 JavaScript 过渡的时候,在 enter
和 leave
中必须使用 done
进行回调。否则,它们将被同步调用,过渡会立即完成。
推荐对于仅使用 JavaScript 过渡的元素添加 v-bind:css="false"
,Vue 会跳过 CSS 的检测。这也可以避免过渡过程中 CSS 的影响。
原生js和库的用法如下:
beforeEnter: function (el) {
el.style.opacity = 0
el.style.transformOrigin = 'left'
},
enter: function (el, done) {
Velocity(el, { opacity: 1, fontSize: '1.4em' }, { duration: 300 })
Velocity(el, { fontSize: '1em' }, { complete: done })
},
八、钩子的done
没有调用done()的话,afterenter和afterleave的钩子函数不会调用。
然后你发现你的show变成了false以后,元素还不会消失,因为vue只有调用了afterleave后才会触发display:none把元素隐藏起来实现元素的v-show效果。如果你在leave中的钩子函数直接写displa:none会发现元素直接消失,因为这个属性没有过渡效果。
Vue有很多种,动画方式js或者css,使用js会让你摆脱css的限制,但是必须要加done(),这样vue才知道动画什么时候结束。
The moment you call done
, Vue considers your transition over and transitions. Without calling it at all, Vue infers from the transition
CSS property on your element that it is a 2s transition. This is why omitting done
works.
你调用done的时刻,vue认为你的动画结束了,如果没有调用done,vue会从css里辨认出过渡的时间。
done在leave钩子上,那么done调用的时间就是leave类删掉样式属性的时间,不是过渡的时间,但是如果done调用的时间小于动画时间是不会有动画的(过渡完之后就会删掉相应属性)代码
九、transition 实现
<transtion>
组件的实现是 export
出 一个对象,从这里我们能看出它会将预先设定好的 props
绑定到 transition
上,而后我们只需对其中的点进行输入即可得到对应的样式输出,具体如何进行的过程,就不需要我们去考虑了
export default {
name: 'transition',
props: transitionProps,
abstract: true,
render (h: Function) {
// 具体 render 等会再看
}
}
其中支持的 props
如下,你可以对 enter
和 leave
的样式进行任意形式的重写
export const transitionProps = {
name: String,
appear: Boolean,
css: Boolean,
mode: String,
type: String,
enterClass: String,
leaveClass: String,
enterToClass: String,
leaveToClass: String,
enterActiveClass: String,
leaveActiveClass: String,
appearClass: String,
appearActiveClass: String,
appearToClass: String,
duration: [Number, String, Object]
}
Props:
name
- string,用于自动生成 CSS 过渡类名。例如:name: 'fade'
将自动拓展为.fade-enter
,.fade-enter-active
等。默认类名为"v"
appear
- boolean,是否在初始渲染时使用过渡。默认为false
。css
- boolean,是否使用 CSS 过渡类。默认为true
。如果设置为false
,将只通过组件事件触发注册的 JavaScript 钩子。type
- string,指定过渡事件类型,侦听过渡何时结束。有效值为"transition"
和"animation"
。默认 Vue.js 将自动检测出持续时间长的为过渡事件类型。mode
- string,控制离开/进入过渡的时间序列。有效的模式有"out-in"
和"in-out"
;默认同时进行。duration
- number | {enter
: number,leave
: number } 指定过渡的持续时间。默认情况下,Vue 会等待过渡所在根元素的第一个transitionend
或animationend
事件。enter-class
- stringleave-class
- stringappear-class
- stringenter-to-class
- stringleave-to-class
- stringappear-to-class
- stringenter-active-class
- stringleave-active-class
- stringappear-active-class
- string
总结
vue 给我们提供了一整套 css 以及 js 的钩子,这些钩子本身都已经帮我定义好并绑定在实例上面,剩下的就是需要我们自己去重写 css 或者 js 钩子函数。