Vue 在插入、更新或者移除 DOM 时,提供多种不同方式的应用过渡效果。包括以下工具:
Vue 提供了 transition
的封装组件,可以给任何元素和组件添加进入/离开过渡。
v-if
)v-show
)我们再使用过渡动画编码时主要有如下几步:
transition
)当我们在HTML中插入或删除包含在 transition
组件中的元素时,Vue 将会做以下处理:
nextTick
概念不同)我们看一个完整示例:
<html>
<head>
<meta charset="UTF-8">
<title>Vue之过渡动画title>
<style>
.fade-enter-active, .fade-leave-active {
transition: opacity 2s;
}
.fade-enter, .fade-leave-to /* .fade-leave-active below version 2.1.8 */ {
opacity: 0;
}
style>
head>
<body>
<div id="app">
<button v-on:click="isShow = !isShow">切换button>
<transition name="fade">
<p v-if="isShow">活着就是胜利,挣钱只是游戏,健康才是目的,快乐才是真谛。p>
transition>
div>
body>
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js">script>
<script type="text/javascript">
const vm = new Vue({
el : "#app",
data: {
isShow: true
}
})
script>
html>
在进入/离开的过渡中,会有 6 个class
切换。
v-enter
:定义进入过渡的开始状态。在元素被插入之前生效,在元素被插入之后的下一帧移除。v-enter-active
:定义进入过渡生效时的状态。在整个进入过渡的阶段中应用,在元素被插入之前生效,在过渡/动画完成之后移除。这个类可以被用来定义进入过渡的过程时间,延迟和曲线函数。v-enter-to
:在元素被插入之后下一帧生效 (与此同时 v-enter
被移除),在过渡/动画完成之后移除。v-leave
:定义离开过渡的开始状态。在离开过渡被触发时立刻生效,下一帧被移除。v-leave-active
:定义离开过渡生效时的状态。在整个离开过渡的阶段中应用,在离开过渡被触发时立刻生效,在过渡/动画完成之后移除。这个类可以被用来定义离开过渡的过程时间,延迟和曲线函数。v-leave-to
:离开过渡的结束状态。在离开过渡被触发之后下一帧生效 (与此同时 v-leave
被删除),在过渡/动画完成之后移除。对于这些在过渡中切换的类名来说,如果你使用一个没有名字的 ,则 `v-` 是这些类名的默认前缀。如果你使用了
,那么 v-enter
会替换为 my-transition-enter
。
v-enter-active
和 v-leave-active
可以控制进入/离开过渡的不同的缓和曲线。
CSS动画用法同CSS 过渡,区别是在动画中 v-enter
类名在节点插入 DOM 后不会立即删除,而是在animationend
事件触发时删除。
<html>
<head>
<meta charset="UTF-8">
<title>Vue之过渡动画title>
<style>
.fade-enter-active, .fade-leave-active {
transition: opacity 2s;
}
.fade-enter, .fade-leave-to {
opacity: 0;
}
/* 设置不同的进入和离开动画, 侧面横向切换效果 */
/* 设置持续时间和动画函数 */
.slide-fade-enter-active {
transition: all .3s ease;
}
.slide-fade-leave-active {
transition: all .8s cubic-bezier(1.0, 0.5, 0.8, 1.0);
}
.slide-fade-enter, .slide-fade-leave-to {
transform: translateX(10px);
opacity: 0;
}
/* 设置弹跳动画切换 */
.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);
}
}
style>
head>
<body>
<div id="app1">
<button v-on:click="isShow = !isShow">切换button>
<transition name="fade">
<p v-if="isShow">直接切换:活着就是胜利,挣钱只是游戏。p>
transition>
div>
<div id="app2">
<button v-on:click="isShow = !isShow">切换button>
<transition name="slide-fade">
<p v-if="isShow">横向切换:健康才是目的,快乐才是真谛。p>
transition>
div>
<div id="app3">
<button v-on:click="isShow = !isShow">切换button>
<transition name="bounce">
<p v-if="isShow">动画切换:寥落古行宫,宫花寂寞红。白头宫女在,闲坐说玄宗。p>
transition>
div>
body>
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js">script>
<script type="text/javascript">
const vm1 = new Vue({
el : "#app1",
data: {
isShow: true
}
})
const vm2 = new Vue({
el : "#app2",
data: {
isShow: true
}
})
const vm3 = new Vue({
el : "#app3",
data: {
isShow: true
}
})
script>
html>
※自定义过渡类名:我们可以通过以下attribute
来自定义过渡类名:
enter-class
enter-active-class
enter-to-class
(2.1.8+)leave-class
leave-active-class
leave-to-class
(2.1.8+)他们的优先级高于普通的类名,这对于 Vue
的过渡系统和其他第三方 CSS 动画库(Animate.css
)结合使用十分有用。
<html>
<head>
<meta charset="UTF-8">
<title>Vue之过渡动画title>
<link href="https://cdn.jsdelivr.net/npm/[email protected]" rel="stylesheet" type="text/css">
head>
<body>
<div id="app4">
<button v-on:click="isShow = !isShow">自定义切换button>
<transition name="custom" enter-active-class="animated tada" leave-active-class="animated bounceOutRight">
<p v-if="isShow">君自故乡来,应知故乡事。来日绮窗前,寒梅著花未?p>
transition>
div>
body>
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js">script>
<script type="text/javascript">
const vm4 = new Vue({
el : "#app4",
data: {
isShow: true
}
})
script>
html>
同时使用过渡和动画
transitionend
或 animationend
,这取决于给元素应用的 CSS 规则。如果你使用其中任何一种,Vue 能自动识别类型并设置监听。如果需要给同一个元素同时设置两种过渡动效,比如 animation
很快的被触发并完成了,而 transition
效果还没结束。在这种情况中,你就需要使用 type
attribute 并设置 animation
或 transition
来明确声明你需要 Vue 监听的类型。显性过渡持续时间
Vue可以自动得出过渡效果的完成时机。默认情况下,Vue 会等待其在过渡效果的根元素的第一个 transitionend
或 animationend
事件。但是我们可以拥有一个属于自己业务定制的一系列过渡效果,其中一些嵌套的内部元素相比于过渡效果的根元素有延迟的或更长的过渡效果。此时可以用组件上的 duration
属性定制一个显性的过渡持续时间 (以毫秒计),也可以定制进入和移出的持续时间。
<transition :duration="1000">...transition>
<transition :duration="{ enter: 500, leave: 800 }">...transition>
可以通过 appear
属性设置节点在初始渲染的过渡,在下面的例子中,无论是 appear
属性还是 v-on:appear
钩子都会生成初始渲染过渡。
这里默认和进入/离开过渡一样,同样也可以自定义 CSS 类名。
<transition
appear
appear-class="custom-appear-class"
appear-to-class="custom-appear-to-class" (2.1.8+)
appear-active-class="custom-appear-active-class"
>
transition>
自定义 JavaScript 钩子:
<transition
appear
v-on:before-appear="customBeforeAppearHook"
v-on:appear="customAppearHook"
v-on:after-appear="customAfterAppearHook"
v-on:appear-cancelled="customAppearCancelledHook"
>
transition>
对于原生标签可以使用 v-if
/v-else
。最常见的多标签过渡是一个列表和描述这个列表为空消息的元素。
<transition>
<table v-if="items.length > 0">
table>
<p v-else>Sorry, no items found.p>
transition>
可以这样使用,但是有一点需要注意:
当有相同标签名的元素切换时,需要通过 key
属性设置唯一的值来标记以让 Vue
区分它们,否则 Vue
为了效率只会替换相同标签内部的内容。即使在技术上没有必要,给在组件中的多个元素设置 key 是一个更好的实践。
示例:
<transition>
<button v-if="isEditing" key="save">
Save
button>
<button v-else key="edit">
Edit
button>
transition>
在一些场景中,也可以通过给同一个元素的 key
设置不同的状态来代替 v-if
和 v-else
,上面的例子可以重写为:
<transition>
<button v-bind:key="isEditing">
{{ isEditing ? 'Save' : 'Edit' }}
button>
transition>
使用多个 v-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'
}
}
}
同时生效的进入和离开的过渡不能满足业务上的所有要求,所以 Vue 提供了过渡模式:
in-out
:新元素先进行过渡,完成之后当前元素过渡离开。out-in
:当前元素先进行过渡,完成之后新元素过渡进入。用 out-in
重写之前的开关按钮过渡:
<transition name="fade" mode="out-in">
transition>
只用添加一个简单的 attribute,就解决了之前的过渡问题而无需任何额外的代码。in-out
模式不是经常用到,但对于一些稍微不同的过渡效果还是有用的。
我们直接使用动态组件来实现多个组件的过渡。
<transition name="component-fade" mode="out-in">
<component v-bind:is="view">component>
transition>
<script type="text/javascript">
new Vue({
el: '#transition-components-demo',
data: {
view: 'v-a'
},
components: {
'v-a': {
template: 'Component A'
},
'v-b': {
template: 'Component B'
}
}
})
script>
<style>
.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;
}
style>