Vue 過渡 & 動畫
本章節(jié)我們主要介紹 Vue.js 的過渡效果與動畫效果。包括如何編寫自定義 CSS 動畫、如何配合第三方 CSS 動畫庫、過渡鉤子函數(shù)的使用、如何使用第三方 JavaScript 動畫庫。本小節(jié)的內(nèi)容相對之前有些難度,同學(xué)們在閱讀一遍之后如果不能完全掌握,建議反復(fù)閱讀,并把本小節(jié)的所有案例自己實(shí)現(xiàn)一遍,相信通過多次的練習(xí)一定可以掌握。
1. 過渡
Vue 在插入、更新或者移除 DOM 時,提供多種不同方式的應(yīng)用過渡效果。
包括以下工具:
1、在 CSS 過渡和動畫中自動應(yīng)用 class;
2、配合使用第三方 CSS 動畫庫,如 Animate.css;
3、在過渡鉤子函數(shù)中使用 JavaScript 直接操作 DOM;
4、配合使用第三方 JavaScript 動畫庫,如 Velocity.js。
語法格式:
使用 transition 組件包裹需要使用過渡效果的 DOM 元素。例如:
<transition name = "transition-name">
<div>...</div>
</transition>
1.1 基本使用
接下來讓我們先看一個淡入淡出效果的實(shí)現(xiàn)代碼:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
.fade-enter-active, .fade-leave-active {
transition: opacity 3s
}
.fade-enter, .fade-leave-to {
opacity: 0
}
</style>
</head>
<body>
<div id = "app">
<button v-on:click = "show = !show">{{ show ? '隱藏' : '顯示'}}</button>
<transition name="fade">
<p v-show = "show" >hello !</p>
</transition>
</div>
</body>
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<script type = "text/javascript">
var vm = new Vue({
el: '#app',
data: {
show:true
},
methods : {
}
});
</script>
</html>
代碼解釋:
- HTML 代碼第 3-5 行,我們使用 transition 組件包裹
<p>
標(biāo)簽,transition 組件指定 name 為 fade,通過 指令 v-show 控制<p>
標(biāo)簽的顯示和隱藏; - HTML 代碼第 2 行,定義按鈕 button,點(diǎn)擊修改 show 的值來控制標(biāo)簽
<p>
的顯示隱藏; - CSS 中我們定義了 4 個樣式;
- JS 代碼第 6 行,定義數(shù)據(jù) show,默認(rèn)值為 true。
那么,transition 組件是如何做到這樣的過渡效果的呢?
我想,同學(xué)們肯定猜想到當(dāng)元素切換狀態(tài)的時候,我們定義的樣式會作用于標(biāo)簽元素 <p>
。那么,到底是不是這樣呢?
打開控制臺,檢索到 <p>
標(biāo)簽上,我們可以清晰地看到:
- 當(dāng)元素隱藏的時候,樣式 fade-leave-active 和 fade-leave-to 會被添加到元素
<p>
上; - 當(dāng)元素顯示的時候,樣式 fade-enter-active 和 fade-enter-to 會被添加到元素
<p>
上。
實(shí)際上 Vue 在元素顯示與隱藏的過渡中,提供了 6 個 class 來切換:
v-enter
:定義進(jìn)入過渡的開始狀態(tài)。在元素被插入之前生效,在元素被插入之后的下一幀移除;v-enter-active
:定義進(jìn)入過渡生效時的狀態(tài)。在整個進(jìn)入過渡的階段中應(yīng)用,在元素被插入之前生效,在過渡 / 動畫完成之后移除。這個類可以被用來定義進(jìn)入過渡的過程時間,延遲和曲線函數(shù);v-enter-to
: 定義進(jìn)入過渡的結(jié)束狀態(tài)。在元素被插入之后下一幀生效 (與此同時v-enter
被移除),在過渡 / 動畫完成之后移除。v-leave
: 定義離開過渡的開始狀態(tài)。在離開過渡被觸發(fā)時立刻生效,下一幀被移除;v-leave-active
:定義離開過渡生效時的狀態(tài)。在整個離開過渡的階段中應(yīng)用,在離開過渡被觸發(fā)時立刻生效,在過渡 / 動畫完成之后移除。這個類可以被用來定義離開過渡的過程時間,延遲和曲線函數(shù);v-leave-to
: 定義離開過渡的結(jié)束狀態(tài)。在離開過渡被觸發(fā)之后下一幀生效 (與此同時v-leave
被刪除),在過渡 / 動畫完成之后移除。
對于這些在過渡中切換的類名來說,如果你使用一個沒有名字的 <transition>
,則 v- 是這些類名的默認(rèn)前綴。如果你使用了 <transition name="test-transition">
,那么 v 會替換為 test-transition。例如:test-transition-enter、test-transition-enter-active、test-transition-leave…
1.2 CSS 過渡
在日常開發(fā)中,我們經(jīng)常會使用 CSS 過渡來實(shí)現(xiàn)一些簡單的動畫效果。接下來我們用一個示例來學(xué)習(xí)如何使用:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
.fade-enter-active {
transition: all .3s ease;
}
.fade-leave-active {
transition: all .3s cubic-bezier(1.0, 0.5, 0.8, 1.0);
}
.fade-enter, .fade-leave-to {
transform: translateY(10px);
opacity: 0;
}
</style>
</head>
<body>
<div id = "app">
<button v-on:click = "show = !show">{{ show ? '顯示' : '隱藏'}}</button>
<transition name = "fade">
<p v-show = "show" >Hello !</p>
</transition>
</div>
</body>
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<script type = "text/javascript">
var vm = new Vue({
el: '#app',
data: {
show:true
}
});
</script>
</html>
代碼解釋:
- HTML 代碼第 3-5 行,我們使用 transition 組件包裹
<p>
標(biāo)簽,transition 組件指定 name 為 fade,通過 指令 v-show 控制<p>
標(biāo)簽的顯示和隱藏; - HTML 代碼第 2 行,定義按鈕 button,點(diǎn)擊修改 show 的值來控制標(biāo)簽
<p>
的顯示隱藏; - CSS 中我們定義了 4 個樣式,通過 transform 控制元素的垂直位移,通過 opacity 控制元素的 透明度,通過 transition 控制元素的過渡效果;
- JS 代碼第 6 行,定義數(shù)據(jù) show,默認(rèn)值為 true。
1.3 CSS 動畫
同樣,我們可以使用 CSS 動畫來實(shí)現(xiàn)元素的過渡效果。CSS 動畫用法類似 CSS 過渡,在過渡的不同階段對應(yīng)的 Class 會作用于元素。但是在動畫中 v-enter 類名在節(jié)點(diǎn)插入 DOM 后不會立即刪除,而是在 animationend 事件觸發(fā)時刪除。
相信同學(xué)們在日常業(yè)務(wù)開發(fā)中一定使用過 Dialog,接下來我們就使用 CSS 動畫來實(shí)現(xiàn)它的過渡效果:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
#app{
text-align: center;
}
.dialog{
width: 100px;
height: 100px;
border: 1px solid #333;
margin: 60px auto;
text-align: center;
line-height: 100px;
}
.bounce-enter-active {
animation: bounce-in 400ms;
}
.bounce-leave-active {
animation: bounce-out 300ms;
}
@keyframes bounce-in {
0% {
transform: scale(0.7);
}
50% {
transform: scale(1.3);
}
100% {
transform: scale(1);
}
}
@keyframes bounce-out {
0% {
transform: scale(1);
}
100% {
transform: scale(0.4);
}
}
</style>
</head>
<body>
<div id = "app">
<button v-on:click = "show = !show">{{ show ? '顯示 Dialog' : '隱藏 Dialog'}}</button>
<transition name = "bounce">
<p v-show = "show" class="dialog">Dialog...</p>
</transition>
</div>
</body>
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<script type = "text/javascript">
var vm = new Vue({
el: '#app',
data: {
show:false
}
});
</script>
</html>
代碼解釋:
- HTML 代碼第 3-5 行,我們使用 transition 組件包裹
<p>
標(biāo)簽,transition 組件指定 name 為 bounce 指令v-show
控制<p>
標(biāo)簽的顯示和隱藏; - HTML 代碼第 2 行,定義按鈕 button,點(diǎn)擊修改 show 的值來控制標(biāo)簽
<p>
的顯示隱藏; - CSS 中我們定義了樣式兩個樣式:
- 元素入場樣式: bounce-enter-active,它執(zhí)行動畫 bounce-in。
- 元素出場樣式: bounce-leave-active,它執(zhí)行動畫 bounce-out。
- JS 代碼第 6 行,定義數(shù)據(jù) show,初始值為 true。
1.4 自定義過渡的類名
在之前的兩個案例中,我們通過給 transition 設(shè)置 name 屬性來指定元素在不同階段的樣式類名,但有時候希望使用自定義的過渡類名,我們可以通過給 transition 設(shè)置以下屬性來達(dá)到需求:
- enter-class
- enter-active-class
- enter-to-class
- leave-class
- leave-active-class
- leave-to-class
自定義過渡的類名優(yōu)先級高于普通的類名,這樣就能很好地與第三方(如:animate.css)的動畫庫結(jié)合使用。
1.5 顯性的過渡持續(xù)時間
在很多情況下,Vue 可以自動得出過渡效果的完成時機(jī)。默認(rèn)情況下,Vue 會等待其在過渡效果的根元素的第一個 transitionend 或 animationend 事件。然而也可以不這樣設(shè)定 —— 比如,我們可以擁有一個精心編排的一系列過渡效果,其中一些嵌套的內(nèi)部元素相比于過渡效果的根元素有延遲的或更長的過渡效果。
在這種情況下你可以用 組件上的 duration 屬性定制一個顯性的過渡持續(xù)時間 (以毫秒計(jì)):
<transition :duration="1000">...</transition>
你也可以定制進(jìn)入和移出的持續(xù)時間:
<transition :duration="{ enter: 400, leave: 600 }">...</transition>
2. JavaScript 鉤子
transition 組件在過渡的不同階段會觸發(fā)相應(yīng)的鉤子函數(shù):
<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"
>
<p>...</p>
</transition>
這些鉤子函數(shù)可以結(jié)合 CSS transitions/animations 使用,也可以單獨(dú)使用。
當(dāng)只用 JavaScript 過渡的時候,在 enter 和 leave 中必須使用 done 進(jìn)行回調(diào)。否則,它們將被同步調(diào)用,過渡會立即完成。
推薦對于僅使用 JavaScript 過渡的元素添加 v-bind:css="false"
,Vue 會跳過 CSS 的檢測。這也可以避免過渡過程中 CSS 的影響。
接下來我們來看一個使用鉤子函數(shù)和 Velocity.js 實(shí)現(xiàn)過渡動畫的例子:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
.hello{
width: 100px;
height: 100px;
border: 1px solid red;
margin: auto;
}
</style>
</head>
<body>
<div id = "app">
<button @click="show = !show">
切換顯示狀態(tài)
</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>
</body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/velocity/1.2.3/velocity.min.js"></script>
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<script type = "text/javascript">
var vm = new Vue({
el: '#app',
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: '20px', rotateZ: '45deg' }, { duration: 600 })
Velocity(el, { rotateZ: '90deg' }, { loop: 3 })
Velocity(el, {
rotateZ: '45deg',
translateY: '30px',
translateX: '30px',
opacity: 0
}, { complete: done })
}
}
});
</script>
</html>
代碼解釋:
- HTML 代碼第 3-12 行,我們使用 transition 組件包裹
<p>
標(biāo)簽,并給 transition 組件綁定監(jiān)聽事件 before-enter、enter、leave; - HTML 代碼第 2 行,定義按鈕 button,點(diǎn)擊修改 show 的值來控制標(biāo)簽
<p>
的顯示隱藏; - JS 代碼第 7 行,定義數(shù)據(jù) show,默認(rèn)值為 false;
- JS 代碼第 10-13 行,定義元素的 beforeEnter 函數(shù),并修改元素的樣式 style;
- JS 代碼第 14-17 行,定義元素的 enter 函數(shù),并執(zhí)行以下操作:
- 使用 Velocity 修改元素的 opacity 和 fontSize,過渡時間為 300。
- 使用 Velocity 修改元素的 fontSize,并在完成時間調(diào)用 done 回調(diào)函數(shù)。
- JS 代碼第 18-27 行,定義元素的 leave 函數(shù),并執(zhí)行以下操作:
- 使用 Velocity 修改元素的 translateX 和 rotateZ,過渡時間為 600。
- 使用 Velocity 修改元素的 rotateZ,并且循環(huán) 3 次。
- 使用 Velocity 修改元素的 rotateZ 、translateY、translateX、opacity,并在完成時間調(diào)用 done 回調(diào)函數(shù)。
3. 初始渲染的過渡
有時候我們希望給元素設(shè)置初始渲染的過渡效果,可以通過給 transition 設(shè)置 appear 的 attribute
:
<transition appear>
<!-- ... -->
</transition>
這里默認(rèn)和進(jìn)入 / 離開過渡一樣,同樣也可以自定義 CSS 類名:
<transition
appear
appear-class="v-appear-class"
appear-to-class="v-appear-to-class"
appear-active-class="v-appear-active-class"
>
<!-- ... -->
</transition>
同樣地,可以使用自定義 JavaScript 鉤子:
<transition
appear
v-on:before-appear="beforeAppear"
v-on:appear="appear"
v-on:after-appear="afterAppear"
v-on:appear-cancelled="appearCancelled"
>
<!-- ... -->
</transition>
接下來我們看一個完整的示例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
.hello{
width: 100px;
height: 100px;
border: 1px solid red;
margin: auto;
}
.v-appear-class{
opacity: 0;
}
.v-appear-to-class{
opacity: 1;
}
.v-appear-active-class{
transition: all 2s;
}
</style>
</head>
<body>
<div id = "app">
<button v-on:click = "show = !show">隱藏</button>
<transition
appear
appear-class="v-appear-class"
appear-to-class="v-appear-to-class"
appear-active-class="v-appear-active-class"
v-on:before-appear="beforeAppear"
v-on:appear="appear"
v-on:after-appear="afterAppear"
v-on:appear-cancelled="appearCancelled"
>
<p v-show = "show" class="hello">Hello !</p>
</transition>
</div>
</body>
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<script type = "text/javascript">
var vm = new Vue({
el: '#app',
data: {
show:true
},
methods: {
beforeAppear() {
console.log('beforeAppear')
},
appear() {
console.log('appear')
},
afterAppear() {
console.log('afterAppear')
},
appearCancelled() {
console.log('appearCancelled')
},
}
});
</script>
</html>
代碼解釋:
- HTML 代碼第 3-14 行,我們使用 transition 組件包裹
<p>
標(biāo)簽,指定 transition 為初次渲染的過渡,并給 transition 組件綁定監(jiān)聽事件: before-appear、appear、after-appear、appear-cancelled; - HTML 代碼第 2 行,定義按鈕 button,點(diǎn)擊修改 show 的值來控制標(biāo)簽
<p>
的顯示隱藏; - JS 代碼第 6 行,定義數(shù)據(jù) show,默認(rèn)值為 false。
4. 小結(jié)
本小節(jié)我們介紹了如何使用 transition 實(shí)現(xiàn)過渡和動畫效果,主要包括以下知識點(diǎn):
- 使用 CSS 過渡配合 transition 實(shí)現(xiàn)過渡效果;
- 使用 CSS 動畫配合 transition 實(shí)現(xiàn)動畫效果;
- 使用 transition 鉤子函數(shù)操作元素 DOM 來實(shí)現(xiàn)動畫;
- 使用 transition 的 appear 屬性實(shí)現(xiàn)初次渲染的動畫效果。