单元素/组件的过渡:transition
这里元素渲染和销毁的过程,就是有一个进入、离开的过渡。这个过渡就有我们看到的动态效果,这个动态效果就由Vue中的 <transition> 包裹并定义其中的变化细节。
<div id="demo"><button v-on:click="show = !show">Toggle</button><transition name="fade"><p v-if="show">hello</p></transition></div>
/*transition 元素的具体过渡效果制定*/.fade-enter-active, .fade-leave-active {transition: opacity .5s;}.fade-enter, .fade-leave-to /* .fade-leave-active below version 2.1.8 */ {opacity: 0;}
当插入或删除包含在transition
组件中的元素时,Vue 将会做以下处理:
自动嗅探目标元素是否应用了 CSS过渡或动画,如果是,在恰当的时机添加/删除CSS类名。
如果过渡组件提供了JavaScript钩子函数,这些钩子函数将在恰当的时机被调用。
如果没有找到JavaScript钩子并且也没有检测到CSS过渡/动画,DOM操作(插入/删除)在下一帧中立即执行。(注意:此指浏览器的逐帧动画机制,和Vue的 nextTick 概念不同)
这里对transition的具体过渡状态变化的制定,在下面具体讲述。 过渡的类名:v-enter、v-enter-to、v-enter-active、
v-leave、v-leave-to、v-leave-active
这里可以这么理解,以上面的例子为例,<p>的渲染与否由 v-if 的show 值决定。
而在这个渲染的过程中,从无到有,有一个“进入”过程,;从有到无的销毁过程,有一个“离开”过程。
可以借由这些过程的类名来分别控制 元素在渲染过程中的动画效果。
如果你使用一个没有名字的<transition>
,则v-
是这些类名的默认前缀。
如果你使用了<transition name="my-transition">
,那么v-enter
会替换为my-transition-enter
。
v-enter-active
和v-leave-active
可以控制进入/离开过渡的不同的缓和曲线,在下面章节会有个示例说明。CSS过渡:没啥好说的,就和前面一样,只是在transition的name属性值——fade,上面定义在不同的进入 和离开的过程中的CSS 过渡效果。
CSS 的transitionCSS动画:CSS的animation自定义过渡的类名:enter-class、enter-to-class、enter-active-class、
leave-class、leave-to-class、leave-active-class
<link href="/npm/animate.css@3.5.1" rel="stylesheet" type="text/css"><div id="example-3"><button @click="show = !show">Toggle render</button><transitionname="custom-classes-transition"enter-active-class="animated tada"leave-active-class="animated bounceOutRight"><p v-if="show">hello</p></transition></div>
这里就是在 <transition> 中使用过渡的类名来定义不同阶段的动画效果。这个类名直接绑定一个动画效果函数,就可以达到定义不同阶段动画效果的目的。同时使用过渡和动画
Vue 为了知道过渡的完成,必须设置相应的事件监听器。它可以是transitionend
或animationend
,这取决于给元素应用的 CSS 规则。如果你使用其中任何一种,Vue 能自动识别类型并设置监听。
但是,在一些场景中,你需要给同一个元素同时设置两种过渡动效,比如animation
很快的被触发并完成了,而transition
效果还没结束。在这种情况中,你就需要使用type
attribute 并设置animation
或transition
来明确声明你需要 Vue 监听的类型。
显性的过渡持续时间
在很多情况下,Vue 可以自动得出过渡效果的完成时机。默认情况下,Vue 会等待其在过渡效果的根元素的第一个transitionend
或animationend
事件。
然而也可以不这样设定——比如,我们可以拥有一个精心编排的一系列过渡效果,其中一些嵌套的内部元素相比于过渡效果的根元素有延迟的或更长的过渡效果。
在这种情况下你可以用<transition>
组件上的duration
prop 定制一个显性的过渡持续时间 (以毫秒计):
<transition :duration="1000">...</transition>
<transition :duration="{ enter: 500, leave: 800 }">...</transition>
JavaScript钩子:在 attribute 中声明 JavaScript 钩子
<transitionv-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>
// ...methods: {// --------// 进入中// --------beforeEnter: function (el) {// ...},// 当与 CSS 结合使用时// 回调函数 done 是可选的enter: function (el, done) {// ...done()},afterEnter: function (el) {// ...},enterCancelled: function (el) {// ...},// --------// 离开时// --------beforeLeave: function (el) {// ...},// 当与 CSS 结合使用时// 回调函数 done 是可选的leave: function (el, done) {// ...done()},afterLeave: function (el) {// ...},// leaveCancelled 只用于 v-show 中leaveCancelled: function (el) {// ...}}
当只用 JavaScript 过渡的时候,在enter
和leave
中必须使用done
进行回调。否则,它们将被同步调用,过渡会立即完成。
推荐对于仅使用 JavaScript 过渡的元素添加v-bind:css="false"
,Vue 会跳过 CSS 的检测。这也可以避免过渡过程中 CSS 的影响。
初始渲染的过渡:appear
可以通过appear
attribute 设置节点在初始渲染的过渡
<transitionappearappear-class="custom-appear-class"appear-to-class="custom-appear-to-class" (2.1.8+)appear-active-class="custom-appear-active-class"><!-- ... --></transition>
自定义JavaScript钩子
<transitionappearv-on:before-appear="customBeforeAppearHook"v-on:appear="customAppearHook"v-on:after-appear="customAfterAppearHook"v-on:appear-cancelled="customAppearCancelledHook"><!-- ... --></transition>
多个元素的过渡: v-if / v-else if 与 else
<transition><button v-if="isEditing" key="save">Save</button><button v-else key="edit">Edit</button></transition>
当有相同标签名的元素切换时,需要通过key
attribute 设置唯一的值来标记以让 Vue 区分它们,否则 Vue 为了效率只会替换相同标签内部的内容。即使在技术上没有必要,给在<transition>
组件中的多个元素设置 key 是一个更好的实践。
可以用三元表达式替代上面的写法:
<transition><button v-bind:key="isEditing">{{ isEditing ? 'Save' : 'Edit' }}</button></transition>
多重 if
<transition><button v-if="docState === 'saved'" key="saved">Edit</button><button v-if="docState === 'edited'" key="edited">Save</button><button v-if="docState === 'editing'" key="editing">Cancel</button></transition>
可以重写为:
<transition><button v-bind:key="docState">{{ buttonMessage }}</button></transition>
// ...computed: {buttonMessage: function () {switch (this.docState) {case 'saved': return 'Edit'case 'edited': return 'Save'case 'editing': return 'Cancel'}}}
过渡模式(不经常使用)
在“on”按钮和“off”按钮的过渡中,两个按钮都被重绘了,一个离开过渡的时候另一个开始进入过渡。这是<transition>
的默认行为 - 进入和离开同时发生。
同时生效的进入和离开的过渡不能满足所有要求,所以 Vue 提供了过渡模式。
in-out
:新元素先进行过渡,完成之后当前元素过渡离开。
out-in
:当前元素先进行过渡,完成之后新元素过渡进入。
<transition name="fade" mode="out-in"><!-- ... the buttons ... --></transition>
多个组件的过渡:就是使用动态组件切换不同的组件
<transition name="component-fade" mode="out-in"><component v-bind:is="view"></component></transition>
new Vue({el: '#transition-components-demo',data: {view: 'v-a'},components: {'v-a': {template: '<div>Component A</div>'},'v-b': {template: '<div>Component B</div>'}}})
.component-fade-enter-active, .component-fade-leave-active {transition: opacity .3s ease;}.component-fade-enter, .component-fade-leave-to/* .component-fade-leave-active for below version 2.1.8 */ {opacity: 0;}
列表过渡: <transition-group> 组件
不同于<transition>
,它会以一个真实元素呈现:默认为一个<span>
。你也可以通过tag
attribute 更换为其他元素。
过渡模式不可用,因为我们不再相互切换特有的元素。
内部元素总是需要提供唯一的key
attribute 值。
CSS 过渡的类将会应用在内部的元素中,而不是这个组/容器本身。
列表的进入/离开过渡列表的排序过渡:v-move
<transition-group>
组件还有一个特殊之处。不仅可以进入和离开动画,还可以改变定位。
类似于前面讲到的enter、leave,这里的 move 也可以通过 在CSS中使用 name attribute来自定义前缀,也可以通过move-class attribute手动设置。(意思就是可以在CSS中使用 .fade-move、或者在<transition> 通过move-class=“...”中使用)可复用的过渡
过渡可以通过 Vue 的组件系统实现复用。要创建一个可复用过渡组件,你需要做的就是将<transition>
或者<transition-group>
作为根组件,然后将任何子组件放置在其中就可以了。
ponent('my-special-transition', {template: '\<transition\name="very-special-transition"\mode="out-in"\v-on:before-enter="beforeEnter"\v-on:after-enter="afterEnter"\>\<slot></slot>\</transition>\',methods: {beforeEnter: function (el) {// ...},afterEnter: function (el) {// ...}}})
函数式组件更适合完成这个任务:
ponent('my-special-transition', {functional: true,render: function (createElement, context) {var data = {props: {name: 'very-special-transition',mode: 'out-in'},on: {beforeEnter: function (el) {// ...},afterEnter: function (el) {// ...}}}return createElement('transition', data, context.children)}})
动态过渡
在 Vue 中即使是过渡也是数据驱动的!动态过渡最基本的例子是通过name
attribute 来绑定动态值。
<transition v-bind:name="transitionName"><!-- ... --></transition>