- <transition> 和 <keep-alive> 两个结合一起用,要确保在内层使用 <keep-alive>
- 所有过渡特性都可以动态绑定,但我们不仅仅只有特性可以利用,还可以通过事件钩子获取上下文中的所有数据,因为事件钩子都是方法。这意味着,根据组件的状态不同,你的 JavaScript 过渡会有不同的表现。
- 过渡模式:进入和离开同时发生是默认行为。in-out:新元素先进行过渡,完成之后当前元素过渡离开。out-in:当前元素先进行过渡,完成之后新元素过渡进入。
<transition name="fade" mode="out-in">
<!-- ... the buttons ... -->
</transition>
- 使用is绑定变量的组件切换时会触发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;
}
- 当有相同标签名的元素切换时,Vue 为了效率只会替换相同标签内部的内容。这样即使该元素包裹在transition中也不会触发动画机制,需要通过 key 特性设置唯一的值来标记以让 Vue 区分它们。当key值改变时,transition就认为包裹的元素被改变需要触发动画机制。
<transition>
<button v-bind:key="isEditing">
{{ isEditing ? 'Save' : 'Edit' }}
</button>
</transition>
- 给任何元素和组件添加进入/离开过渡,当插入或删除包含在 transition 组件中的元素时,先检测是否应用了 CSS 过渡或动画,再检查是否提供了 JavaScript 钩子函数
<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;
}
css过渡动画类
- v-enter:定义进入过渡的开始状态。在元素被插入之前生效,在元素被插入之后的下一帧移除。(插入后opacity为1,这时存在过渡时间,所以有动画效果。总结,从v-enter类的样式过渡到v-enter-to的样式,如果没又v-enter实际上是过渡到插入元素自身的样式)CSS 动画用法同 CSS 过渡,区别是在动画中 v-enter 类名在节点插入 DOM 后不会立即删除,而是在 animationend 事件触发时删除。
- v-enter-active:定义进入过渡生效时的状态。在整个进入过渡的阶段中应用,在元素被插入之前生效,在过渡/动画完成之后移除。这个类可以被用来定义进入过渡的过程时间,延迟和曲线函数。
- v-enter-to: 2.1.8版及以上 定义进入过渡的结束状态。在元素被插入之后下一帧生效 (与此同时 v-enter 被移除),在过渡/动画完成之后移除。
- v-leave: 定义离开过渡的开始状态。在离开过渡被触发时立刻生效,下一帧被移除。
- v-leave-active:定义离开过渡生效时的状态。在整个离开过渡的阶段中应用,在离开过渡被触发时立刻生效,在过渡/动画完成之后移除。这个类可以被用来定义离开过渡的过程时间,延迟和曲线函数。
- v-leave-to: 2.1.8版及以上 定义离开过渡的结束状态。在离开过渡被触发之后下一帧生效 (与此同时 v-leave 被删除),在过渡/动画完成之后移除。
如果你使用一个没有名字的 <transition>,则 v- 是这些类名的默认前缀。
可以通过以下特性来自定义过渡类名,这个自定义的类名(可以多个)将直接依据规则添加到元素上(动画的使用方法)
// enter-class
// enter-active-class 运行时的类
// enter-to-class (2.1.8+)
// leave-class
// leave-active-class
// leave-to-class (2.1.8+)
<link href="https://cdn.jsdelivr.net/npm/animate.css@3.5.1" rel="stylesheet" type="text/css">
// webpack使用
// cnpm i animate.css --save
// import 'animate.css'
<div id="example-3">
<button @click="show = !show">
Toggle render
</button>
<transition
name="custom-classes-transition"
enter-active-
leave-active-
>
<p v-if="show">hello</p>
</transition>
</div>
- Vue 为了知道过渡的完成,设置了相应的事件监听器 transitionend 或 animationend。当给同一个元素同时设置两种过渡动效,比如 animation 很快的被触发并完成了,而 transition 效果还没结束。在这种情况中,你就需要使用 type 特性并设置 animation 或 transition 来明确声明你需要 Vue 监听的类型。默认 Vue 会等待其在过渡效果的根元素的第一个 transitionend 或 animationend 事件。
<transition
name="custom-classes-transition"
enter-active-
leave-active-
type="transition" // animation
>
<p v-if="show">hello</p>
</transition>
- 可以用 <transition> 组件上的 duration 属性定制一个显性的过渡持续时间 (以毫秒计):动画执行时间依然受过渡和动画CSS控制,但是-to类的添加和元素的删除受这个时间限定
<transition :duration="1000">...</transition>
// 你也可以定制进入和移出的持续时间:
<transition :duration="{ enter: 500, leave: 800 }">...</transition>
- 可以在属性中声明 JavaScript 钩子
<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>
// ...
methods: {
// --------
// 进入中
// --------
beforeEnter: function (el) {
// ...
},
// 当与 CSS 结合使用时
// 回调函数 done 是可选的
enter: function (el, done) {
// ...
done() // 当只用 JavaScript 过渡的时候,在 enter 和 leave 中必须使用 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) {
// ...
}
}
new Vue({
el: '#example-4',
data: {
show: false
},
methods: {
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.js动画库提供
Velocity(el, { fontSize: '1em' }, { complete: done })
},
leave: function (el, done) {
Velocity(el, { translateX: '15px', rotateZ: '50deg' }, { duration: 600 })
Velocity(el, { rotateZ: '100deg' }, { loop: 2 })
Velocity(el, {
rotateZ: '45deg',
translateY: '30px',
translateX: '30px',
opacity: 0
}, { complete: done })
}
}
})
- 推荐对于仅使用 JavaScript 过渡的元素添加 v-bind:css="false",Vue 会跳过 CSS 的检测。这也可以避免过渡过程中 CSS 的影响。
<transition
v-on:before-enter="beforeEnter"
v-on:enter="enter"
v-on:leave="leave"
v-bind:css="false"
>
<p v-if="show">
Demo
</p>
</transition>
- 可以通过 appear 特性设置节点在初始渲染的过渡
<transition appear>
<!-- ... -->
</transition>
<transition
appear
appear-
appear-to- (2.1.8+)
appear-active-
>
<!-- ... -->
</transition>
<transition
appear
v-on:before-appear="customBeforeAppearHook"
v-on:appear="customAppearHook"
v-on:after-appear="customAfterAppearHook"
v-on:appear-cancelled="customAppearCancelledHook"
>
<!-- ... -->
</transition>
transition-group - 不同于 <transition>,它会以一个真实元素呈现:默认为一个 <span>。你也可以通过 tag 特性更换为其他元素。
- 过渡模式不可用
- 内部元素 总是需要 提供唯一的 key 属性值
- 内部子元素添加或删除时添加对应的类或者执行对应的函数
<div class="demo">
<button v-on:click="add">Add</button>
<button v-on:click="remove">Remove</button>
<transition-group name="list" tag="p">
<span v-for="item in items" v-bind:key="item" class="list-item">
{{ item }}
</span>
</transition-group>
</div>
.list-enter-active, .list-leave-active {
transition: all 1s;
}
.list-enter, .list-leave-to
/* .list-leave-active 只能用于 2.1.8 之后的版本 */ {
opacity: 0;
transform: translateY(30px);
}
- 特别的是他拥有v-move 特性,它会在元素的改变定位的过程中应用(v-move并不是一个vue指令,不需要明写入代码)(使用FLIP 技术 :计算元素的初始位置和最终位置,通过2D/3D转变执行动画,所以改变的是定位。实际是渲染位置的改变,触发了FLIP的使用,导致了定位的改变,添加v-move class)
- 像之前的类名一样,可以通过 name 属性来自定义前缀,也可以通过 move-class 属性手动设置
- 元素渲染位置发生改变就会被添加对应的move的class,比如在-leave-active设置被移除的元素
position: absolute;
那么之后的元素都会因为位置发生改变被添加move的class(被移除的这个元素position改变为absolute,却没有动画效果,是因为当正常流的元素设置position: absolute却没有设置left等位置值时,它的渲染位置是不会发生改变的); - 添加元素时也一样,元素先添加,然后通过添加类显示动画;
- 删除时先添加类显示动画,最后删除。
- 需要注意的是使用 FLIP 过渡的元素不能设置为 display: inline 。作为替代方案,可以设置为 display: inline-block 或者放置于 flex 中
- 根据key判断是否同一个元素,从而判断它的渲染位置是否改变
<div class="demo">
<button v-on:click="shuffle">Shuffle</button>
<transition-group name="flip-list" tag="ul">
<li v-for="item in items" v-bind:key="item">
{{ item }}
</li>
</transition-group>
</div>
new Vue({
el: '#flip-list-demo',
data: {
items: [1,2,3,4,5,6,7,8,9]
},
methods: {
shuffle: function () {
this.items = _.shuffle(this.items)
}
}
})
.flip-list-move {
transition: transform 1s; // 过渡了2D/3D转变属性
}