Vue 提供了多种方式来实现过渡效果。
将元素或组件放在
如果没有找到 JavaScript 过渡钩子和 CSS 过渡/动画,DOM 操作在下一帧中立即执行。
Vue提供了 6 个可以自动生成的 CSS 类名,如下图。
可以自动生成的类名是指给 transition 组件的 name 属性指定一个值,假设是 fade,那么该 name 将自动扩展生成 .fade-enter、.fade-enter-active、.fade-enter-to等上述6个类,并应用在 transition 组件里的过渡元素或组件上。
示例:
DOCTYPE html>
<html>
<head>
<title>Vue 2 过渡 Demotitle>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js">script>
<style>
.fade-enter {
opacity: 0;
transform: translateY(-20px);
}
.fade-enter-active {
transition: all 0.3s ease;
}
.fade-enter-to {
opacity: 1;
transform: translateY(0);
}
.fade-leave {
opacity: 1;
}
.fade-leave-active {
transition: opacity 0.5s ease;
}
.fade-leave-to {
opacity: 0;
}
style>
head>
<body>
<div id="app">
<button @click="showElement=!showElement">显示/隐藏元素button>
<transition name="fade">
<div v-if="showElement">
你好
div>
transition>
div>
<script>
new Vue({
el: '#app',
data: {
showElement: false
},
});
script>
body>
html>
如果想结合使用 animate.css 动画库,可以在 transition 组件使用以下 props 来指定类名:
示例:
DOCTYPE html>
<html>
<head>
<title>Vue 2 过渡 Demotitle>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js">script>
<link href="https://cdn.jsdelivr.net/npm/[email protected]" rel="stylesheet" type="text/css">
head>
<body>
<div id="app">
<button @click="showElement=!showElement">显示/隐藏元素button>
<transition
enter-active-class="animated fadeInLeft"
leave-active-class="animated fadeOut">
<div v-if="showElement">
你好
div>
transition>
div>
<script>
new Vue({
el: '#app',
data: {
showElement: false
},
});
script>
body>
html>
Animate 动画演示
通过设置 transition 组件的 type 属性来指定要监听的过渡事件类型(transitionend 和 animationend)。
type 值可以是 transition 或 animation。
示例:
DOCTYPE html>
<html>
<head>
<title>Vue 2 过渡 Demotitle>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js">script>
<link href="https://cdn.jsdelivr.net/npm/[email protected]" rel="stylesheet" type="text/css">
<style>
.fade-enter {
opacity: 0;
transform: translateY(-20px);
}
.fade-enter-active {
transition: all 0.3s ease;
}
.fade-enter-to {
opacity: 1;
transform: translateY(0);
}
.fade-leave {
opacity: 1;
}
.fade-leave-active {
transition: opacity 0.5s ease;
}
.fade-leave-to {
opacity: 0;
}
style>
head>
<body>
<div id="app">
<button @click="toggleElement">Toggle Elementbutton>
<transition name="fade"
type="transition"
>
<div v-if="showElement" key="element">Hello, Vue!div>
transition>
<transition name="bounce"
enter-active-class="animated bounceIn"
leave-active-class="animated bounceOut"
type="animation"
>
<div v-if="showElement" key="element">Hello, vue!div>
transition>
div>
<script>
new Vue({
el: '#app',
data: {
showElement: false
},
methods: {
toggleElement() {
this.showElement = !this.showElement;
},
},
});
script>
body>
html>
默认情况下,Vue 会等待过渡所在根元素的第一个 transitionend
或 animationend
事件。
我们可以使用 transition 组件上的 duration prop 定制一个显示的过渡持续时间,以毫秒为单位。
<transition :duration="1000">...transition>
<transition :duration="{ enter: 500, leave: 800 }">...transition>
共 8 个:
注意点:
v-bind:css="false"
,Vue 会跳过 CSS 的检测。这也可以避免过渡过程中 CSS 的影响。DOCTYPE html>
<html>
<head>
<title>Vue 2 过渡 Demotitle>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js">script>
<link href="https://cdn.jsdelivr.net/npm/[email protected]" rel="stylesheet" type="text/css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/velocity/1.2.3/velocity.min.js">script>
style>
head>
<body>
<div id="app">
<button @click="toggleElement">切换元素button>
<transition name="custom-transition" @before-enter="beforeEnter" @enter="enter" @leave="leave">
<div v-if="showElement" key="element">Hello, Vue!div>
transition>
div>
<script>
new Vue({
el: '#app',
data: {
showElement: false
},
methods: {
toggleElement() {
this.showElement = !this.showElement;
},
beforeEnter(el) {
// 在进入过渡开始之前调用
el.style.opacity = 0;
},
enter(el, done) {
// 在进入过渡的主要阶段调用
Velocity(el, { opacity: 1, translateY: '0px',fontSize: '2em' }, { duration: 1000, complete: done });
Velocity(el, { fontSize: '1em' }, { complete: done })
},
leave(el, done) {
// 在离开过渡的主要阶段调用
Velocity(el, { opacity: 0, translateY: '20px' }, { duration: 1000, complete: done });
},
}
});
script>
body>
html>
启用初始渲染的过渡:
<transition
appear
appear-class=""
appear-active-class=""
appear-to-class=""
v-on:before-appear=""
v-on:appear=""
v-on:after-appear=""
v-on:appear-cancelled=""
>
transition>
如果想实现多个原生元素的切换过渡,可以使用条件渲染的相关指令。
如果切换的元素标签名相同,比如都是 button ,那么最好给它们设置唯一的key
属性,否则可能出现过渡效果不生效或没按设置过渡的情况。
DOCTYPE html>
<html>
<head>
<title>Vue 2 过渡 Demotitle>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js">script>
<link href="https://cdn.jsdelivr.net/npm/[email protected]" rel="stylesheet" type="text/css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/velocity/1.2.3/velocity.min.js">script>
style>
head>
<body>
<div id="app">
<button @click="toggleElement">切换元素button>
<transition @before-enter="beforeEnter" @enter="enter" @leave="leave">
<div v-if="showElement" key="el1">Hello, girls!div>
<div v-else key="el2">Hello, boys!div>
transition>
div>
<script>
new Vue({
el: '#app',
data: {
showElement: false
},
methods: {
toggleElement() {
this.showElement = !this.showElement;
},
beforeEnter(el) {
// 在进入过渡开始之前调用
el.style.opacity = 0;
},
enter(el, done) {
// 在进入过渡的主要阶段调用
Velocity(el, { opacity: 1, translateY: '0px',fontSize: '2em' }, { duration: 1000, complete: done });
Velocity(el, { fontSize: '1em' }, { complete: done })
},
leave(el, done) {
// 在离开过渡的主要阶段调用
Velocity(el, { opacity: 0, translateY: '20px' }, { duration: 1000, complete: done });
},
}
});
script>
body>
html>
也可以使用绑定动态 property 的方式来替代使用了多个 v-if 的相同标签名元素。
<transition>
<div v-if="show==='el1'" key="el1">el1div>
<div v-if="show==='el2'" key="el2">el2div>
transition>
替换成
<transition>
<div :key="el">eldiv>
transition>
如上图中,前一个元素的过渡结束时,另一个元素的过渡开始,这有时候并不是我们想要的效果。
于是,Vue 提供了过渡模式。
<transition name="fade" mode="out-in">
transition>
mode 可以为以下值:
So cool!
多个元素我们可以使用 key attribute,对于多个组件,我们可以使用更为简单的 is attribute,即动态组件。
<transition name="component-fade" mode="out-in">
<component v-bind:is="view">component>
transition>
前面所讲都是针对单个节点或者多个节点中的一个。
而对于有多个节点的列表的渲染,我们使用 transition-group
组件。
transition-group
组件的特点:
transition
不同,它以一个真实的元素存在,默认为 span,可以使用 tag attribute 修改。DOCTYPE html>
<html>
<head>
<title>Vue 2 过渡 Demotitle>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js">script>
<link href="https://cdn.jsdelivr.net/npm/[email protected]" rel="stylesheet" type="text/css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/velocity/1.2.3/velocity.min.js">script>
style>
<style>
.list-enter-active,
.list-leave-active {
transition: opacity,transform 0.5s;
}
.list-enter,
.list-leave-to {
opacity: 0;
transform: translateX(60px);
}
.list-item {
list-style:decimal-leading-zero;
margin: 5px;
padding: 5px;
background-color: #f0f0f0;
border: 1px solid #ddd;
border-radius: 5px;
width: fit-content;
}
style>
head>
<body>
<div id="app">
<button @click="addItem">Add Itembutton>
<button @click="removeItem">Remove Itembutton>
<transition-group name="list" tag="ul">
<li v-for="item in items" :key="item.id" class="list-item">
{{item.text}}
li>
transition-group>
div>
<script>
new Vue({
el: '#app',
data: {
items: [],
nextItemId: 0
},
methods: {
addItem() {
let randomIndex=Math.floor(Math.random()*this.items.length);
this.items.splice(randomIndex,0, {
id: this.nextItemId++,
text: `Item ${this.nextItemId}`
});
},
removeItem() {
let randomIndex = Math.floor(Math.random()*this.items.length);
this.items.splice(randomIndex, 1);
}
},
});
script>
body>
html>
不仅可以给进入/离开添加过渡,当列表的元素位置发生变化时,也可以产生过渡效果,通过 move-class
attribute自定义类名来实现,也可以使用 name
作为前缀。
例如当 name="list"
时:
.list-move {
transition: transform 1s;
}
这个可以解决列表过渡不够平滑的问题。
如果想给所有的变动都添加过渡动画,那么可以按以下方法做:
DOCTYPE html>
<html>
<head>
<title>Vue 2 过渡 Demotitle>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js">script>
<link href="https://cdn.jsdelivr.net/npm/[email protected]" rel="stylesheet" type="text/css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/velocity/1.2.3/velocity.min.js">script>
style>
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.14.1/lodash.min.js">script>
<style>
.list-enter,
.list-leave-to {
opacity: 0;
transform: translateX(30px);
}
.list-leave-active{
position: absolute;
}
.list-item {
transition: all 1s;
list-style: none;
margin: 5px;
padding: 5px;
background-color: #f0f0f0;
border: 1px solid #ddd;
border-radius: 5px;
width: fit-content;
}
style>
head>
<body>
<div id="app">
<button @click="addItem">Add Itembutton>
<button @click="removeItem">Remove Itembutton>
<button @click="shuffleItems">Shuffle Itemsbutton>
<transition-group name="list" tag="ul">
<li v-for="item in items" :key="item.id" class="list-item">
{{item.text}}
li>
transition-group>
div>
<script>
new Vue({
el: '#app',
data: {
items: [],
nextItemId: 0
},
methods: {
addItem() {
let randomIndex = Math.floor(Math.random() * this.items.length);
this.items.splice(randomIndex, 0, {
id: this.nextItemId++,
text: `Item ${this.nextItemId}`
});
},
removeItem() {
let randomIndex = Math.floor(Math.random() * this.items.length);
this.items.splice(randomIndex, 1);
},
shuffleItems() {
this.items = _.shuffle(this.items);
}
},
});
script>
body>
html>
这被叫做 FLIP 过渡,使用这种过渡方式的元素不能设置为 display:inline
。
通过 HTML 的 data 属性与 JavaScript 进行通信来实现交错排序。
<li
v-for="(item, index) in computedList"
v-bind:key="item.msg"
v-bind:data-index="index"
>{{ item.msg }}li>
enter: function (el, done) {
var delay = el.dataset.index * 150; // 通过 data-index 获取元素的索引,然后计算延迟时间
setTimeout(function () {
Velocity(
el,
{ opacity: 1, height: '1.6em' }, // 使用 Velocity.js 库来应用 CSS 属性的动画效果
{ complete: done } // 动画完成后调用 done 回调函数来通知 Vue.js 过渡完成
);
}, delay);
},
每个元素都有不同的延迟,以实现交错的过渡效果。
使用 template :
Vue.component('my-special-transition', {
template: '\
\
\
\
',
methods: {
beforeEnter: function (el) {
// ...
},
afterEnter: function (el) {
// ...
}
}
})
使用 函数式组件 :
Vue.component('reusable-transition', {
functional: true,
render: function (createElement, context) {
var data = {
props: {
name: 'reusable-transition',
mode: 'out-in'
},
on: {
beforeEnter: function (el) {
// ...
},
afterEnter: function (el) {
// ...
}
}
}
return createElement('transition', data, context.children)
}
})
使用 单文件组件:
总之,可复用过渡就是以 transition
或 transition-group
作为根元素。
我们可以根据组件的状态或属性动态地应用不同的过渡效果。
通常涉及使用过渡的不同名称、条件语句和组件的动态属性。
DOCTYPE html>
<html>
<head>
<title>Vue 2 过渡 Demotitle>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js">script>
<link href="https://cdn.jsdelivr.net/npm/[email protected]" rel="stylesheet" type="text/css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/velocity/1.2.3/velocity.min.js">script>
<style>
.default-enter,
.default-leave-to {
opacity: 0;
transform: translateX(30px);
}
.slide-enter,
.slide-leave-to {
transform: translateY(30px);
opacity: 0;
}
.default-leave-active,
.slide-leave-active{
position: absolute;
}
.list-item {
transition: all 1s;
}
style>
head>
<body>
<div id="app">
<input v-model="newTodo" @keyup.enter="addTodo" placeholder="添加新任务">
<button @click="toggleTransition">切换过渡方式button>
<transition-group :name="dynamicTransitionName" tag="ul">
<li v-for="todo in todos" :key="todo.id" class="list-item">
{{todo.text}}
<button @click="removeTodo(index)">删除button>
li>
transition-group>
div>
<script>
new Vue({
el: '#app',
data: {
dynamicTransitionName: 'default',
newTodo: '',
todos: [],
nextID: 0
},
methods: {
addTodo() {
if (this.newTodo.trim() !== '') {
this.todos.push({id:this.nextID++, text: this.newTodo });
this.newTodo = '';
}
},
removeTodo(index) {
this.todos.splice(index, 1);
},
toggleTransition(){
this.dynamicTransitionName=this.dynamicTransitionName==='default'?'slide':'default';
}
},
});
script>
body>
html>