Vue 在插入、更新或者移除 DOM 时,提供多种不同方式的应用过渡效果。它们包括:
(1)在CSS过渡和动画中自动应用 class
(2)配合使用第三方 CSS 动画库,引入animate.css实现效果过渡
(3)配合使用第三方 JavaScript 动画库,引入velocity.js实现效果过渡
(4)引入tween.js数值实现数值过渡
在CSS过渡和动画中自动应用 class
Vue 提供了 transition 的封装组件,在下列情形中,可以给任何元素和组件添加 entering/leaving 过渡。也就是说,使用这种方法实现过渡效果,需要将实现效果的标签放到<transition ></transition>内。当插入或删除包含在 transition 组件中的元素时,Vue 将会做以下处理:
1. 自动嗅探目标元素是否应用了 CSS 过渡或动画,如果是,在恰当的时机添加/删除 CSS 类名。
2. 如果过渡组件提供了 JavaScript 钩子函数,这些钩子函数将在恰当的时机被调用。
3. 如果没有找到 JavaScript 钩子并且也没有检测到 CSS 过渡/动画,DOM 操作 (插入/删除) 在下一帧中立即执行。(注意:此指浏览器逐帧动画机制,和 Vue 的 nextTick 概念不同)
参考Demo:
<style>
.fade-enter-active,
.fade-leave-active {
transition: opacity .5s/*transition用法:属性值 时长。表示某属性值变化过程所需时长*/
}
.fade-enter,
.fade-leave-to {
opacity: 0
}
</style>
<div id="app">
<button v-on:click="show = !show">
Toggle
</button>
<transition name="fade">
<p v-if="show">大家好,这里是过渡动画测试</p>
</transition>
</div>
<script>
var vue = new Vue({
el: "#app",
data: {
show: true
}
});
</script>
点击按钮即可看到过渡效果。
(注)从上面例子可看到<transition name="fade">定义了name为'fade',这个'fade'的作用在于命名过渡动画样式,如上例子中的样式.fade-?-?。这是这种过渡效果的命名规则。在进入/离开的过渡中,会有 6 个 class 切换:
.name-enter:定义进入过渡的开始状态,在元素被插入时生效,在下一个帧移除。
.name-enter-active:定义过渡的状态。在元素整个过渡过程中作用,这个类可以被用来定义过渡的过程时间,延迟和曲线函数。
.name-enter-to: 2.1.8版及以上,定义进入过渡的结束状态。在元素被插入一帧后生效。
.name-leave: 定义离开过渡的开始状态,在离开过渡被触发时生效,在下一个帧移除。
.name-leave-active:定义过渡的状态。在元素整个过渡过程中作用,在离开过渡被触发后立即生效,这个类可以被用来定义过渡的过程时间,延迟和曲线函数。
.name-leave-to: 2.1.8版及以上 定义离开过渡的结束状态。在离开过渡被触发一帧后生效 (于此同时 v-leave 被删除)。
上例中的运行过程如图所示:

引入animate.css实现效果过渡
这种方法需要引用animate.css,百度上搜一下即可下载。它在进入/离开的过渡中,也会有 6 个 状态切换,与上一种类似:
enter-class
enter-active-class
enter-to-class (2.1.8+)
leave-class
leave-active-class
leave-to-class (2.1.8+)
参考Demo:
<link href="https://cdn.jsdelivr.net/npm/animate.css@3.5.1" rel="stylesheet" type="text/css">
<!-- animate.css过渡,地址:https://daneden.github.io/animate.css/ -->
<div id="animatecss">
<button @click="show = !show">
Toggle render
</button>
<transition name="custom-classes-transition" enter-active-class="animated bounceInDown" leave-active-class="animated bounceOutRight">
<p v-if="show">hello</p>
</transition>
</div>
<script>
var animatecss = new Vue({
el: '#animatecss',
data: {
show: true
}
})
</script>
(注)所包含的动画效果可以到animate.css官网查看。
引入velocity.js实现效果过渡
通过使用transition的钩子函数监听,监听状态类别如下:
<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>
参考Demo:
<script src="https://cdnjs.cloudflare.com/ajax/libs/velocity/1.2.3/velocity.min.js"></script>
<!-- velocity过渡 -->
<div id="velocityjs">
<button @click="show = !show">
Toggle
</button>
<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>
</div>
<br />
<!-- velocity数组过渡 -->
<div id="staggered-list-demo">
<input v-model="query">
<transition-group name="staggered-fade" tag="ul" v-bind:css="false" v-on:before-enter="beforeEnter" v-on:enter="enter" v-on:leave="leave">
<li v-for="(item, index) in computedList" v-bind:key="item.msg" v-bind:data-index="index">{{ item.msg }}</li>
</transition-group>
</div>
<script>
var velocity = new Vue({
el: '#velocityjs',
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(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
})
}
}
})
var velocity2 = new Vue({
el: '#staggered-list-demo',
data: {
query: '',
list: [{
msg: 'Bruce Lee'
},
{
msg: 'Jackie Chan'
},
{
msg: 'Chuck Norris'
},
{
msg: 'Jet Li'
},
{
msg: 'Kung Fury'
}
]
},
computed: {
computedList: function() {
var vm = this
return this.list.filter(function(item) {
return item.msg.toLowerCase().indexOf(vm.query.toLowerCase()) !== -1
})
}
},
methods: {
beforeEnter: function(el) {
el.style.opacity = 0
el.style.height = 0
},
enter: function(el, done) {
var delay = el.dataset.index * 150;
setTimeout(function() {
Velocity(
el, {
opacity: 1,
height: '1.6em'
}, {
complete: done
}
)
}, delay)
},
leave: function(el, done) {
var delay = el.dataset.index * 150
setTimeout(function() {
Velocity(
el, {
opacity: 0,
height: 0
}, {
complete: done
}
)
}, delay)
}
}
});
</script>
引入tween.js数值实现数值过渡
这种过渡效果是:当数字变化时,有一个动态的数字滚动效果。
参考Demo:
<script src="https://cdn.jsdelivr.net/npm/tween.js@16.3.4"></script>
<!-- tween.js数值过渡 -->
<div id="numDemo">
<label>{{animatedNumber}}</label>
<button @click="numChange">改变数值</button>
</div>
<script>
var num = new Vue({
el: '#numDemo',
data: {
animatedNumber: 0
},
methods: {
numChange: function() {
var vm = this;
var oldValue = parseInt(this.animatedNumber);
var newValue = parseInt(this.animatedNumber) + 999;
function animate() {
if(TWEEN.update()) {
requestAnimationFrame(animate)
}
}
new TWEEN.Tween({
tweeningNumber: oldValue
})
.easing(TWEEN.Easing.Quadratic.Out)
.to({
tweeningNumber: newValue
}, 500)
.onUpdate(function() {
vm.animatedNumber = this.tweeningNumber.toFixed(0)
})
.start();
animate();
}
}
});
</script>