vue中的過渡與動畫
過濾
把需要添加動畫效果的DIV放到transition標籤
之後就會發生以下3個步驟
-
自動嗅探目標元素是否應用了 CSS 過渡或動畫,如果是,在恰當的時機添加/刪除 CSS 類名(等下要寫的6個類名)。
-
如果過渡組件提供了 JavaScript 鉤子函數,這些鉤子函數將在恰當的時機被調用。
-
如果沒有找到 JavaScript 鉤子並且也沒有檢測到 CSS 過渡/動畫,DOM 操作 (插入/刪除) 在下一幀中立即執行。(注意:此指瀏覽器逐幀動畫機制,和 Vue 的
nextTick
概念不同)
類名
v-enter
:定義進入過渡的開始狀態。在元素被插入之前生效,在元素被插入之後的下一幀移除。
v-enter-active
:定義進入過渡生效時的狀態。在整個進入過渡的階段中應用,在元素被插入之前生效,在過渡/動畫完成之後移除。這個類可以被用來定義進入過渡的過程時間,延遲和曲線函數。
v-enter-to
: 2.1.8版及以上 定義進入過渡的結束狀態。在元素被插入之後下一幀生效 (與此同時 v-enter
被移除),在過渡/動畫完成之後移除。
v-leave
: 定義離開過渡的開始狀態。在離開過渡被觸發時立刻生效,下一幀被移除。
v-leave-active
:定義離開過渡生效時的狀態。在整個離開過渡的階段中應用,在離開過渡被觸發時立刻生效,在過渡/動畫完成之後移除。這個類可以被用來定義離開過渡的過程時間,延遲和曲線函數。
v-leave-to
: 2.1.8版及以上 定義離開過渡的結束狀態。在離開過渡被觸發之後下一幀生效 (與此同時 v-leave
被刪除),在過渡/動畫完成之後移除。
插入
其實是看完了文檔我也是一臉懵逼,看到這裏其實有很多問題就出來了,下面我們一一列舉一一解答
- 什麼是定義進入/離開過渡
- 什麼是在元素被插入之前,這個插入是插入到什麼地方
- 當我們自身元素的css樣式和v-enter,v-enter-to,v-leave,v-leave-to會出現重複嗎?,是會覆蓋還是不會覆蓋,而且覆蓋是誰覆蓋誰,是自身的樣式權重高呢,還是v-enter...呢?
- v-if和v-show的區別
1.什麼是定義進入/離開過渡
進入過渡:元素顯示的過程
離開過渡:元素離開的過程
以前我理解這個就是有一個地方無法理解,明明不管元素是顯示還是隱藏他們都是一個過渡過程,那麼其實他們(顯示過程或離開過程)都是代表的進入過渡,對吧,我以前一直以爲是文檔表達的不清楚,但是後來我發現我自己太天真了,嘿嘿/斜眼笑。
2.什麼是在元素被插入之前,這個插入是插入到什麼地方
爲什麼我會有這個問題呢?因爲v-if和v-show的區別大家應該都知道v-if是通過DOM的增刪改變的顯示隱藏,但是v-show呢?他可是通過display來顯示和隱藏的啊,如果你說你只可以用v-if那是插入還差不多,但是你如果用的是v-show也可以達到效果,但是那你的文檔的定義感覺有點問題啊是把?後來我發現我天真了,爲什麼呢?因爲其實我們知道除了DOM樹,還有一個瀏覽器的--渲染樹,什麼是渲染樹呢?這裏有我找的一篇文章,渲染樹其實就是一個依賴DOM樹,先有DOM樹,再根據DOM去生成瀏覽器是渲染樹,再文章中說了一句很關鍵的話:如果元素的display屬性被設置成了none,或者如果元素的子孫繼承了display:none,renderer不會被創建。節點的子類和display屬性一起決定爲該節點創建什麼樣的渲染器,說明了其實就算是v-show爲false他的DOM依然在,但是也是是單單在DOM樹上,在瀏覽器的渲染樹上是不存在的所以纔有了插入的在一個說法,並且第一個問題的進入/離開也有了很好的介紹,就是進入離開渲染樹
3.當我們自身元素的css樣式和v-enter,v-enter-to...是否會發出重複呢
-
重複是否會出錯
-
發生覆蓋,那麼誰覆蓋誰
這裏我建議當我們要過渡一個元素的屬性的時候,我們不要再這個元素上定義這個屬性值
案例
過渡改變div的高度
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<script src="./node_modules/vue/dist/vue.js"></script>
<style>
.box{
border: 1px solid saddlebrown;
background-color: brown;
}
.box p{
margin: 0;
height: 156px;
border: 1px solid saddlebrown;
}
.bounce-enter-active,.bounce-leave-active {
transition: all 1s ease;
}
.bounce-leave,.bounce-enter-to{
height: 156px;
}
.bounce-enter,.bounce-leave-to {
height: 0;
color: chartreuse;
}
</style>
</head>
<body>
<div id="example-2">
<button @click="show = !show">Toggle show</button>
<transition name="bounce">
<div class="box" v-show='show'>
<p>我的高度我156px;</p>
</div>
</transition>
</div>
<script>
new Vue({
el: '#example-2',
data: {
show: false
}
})
</script>
</body>
</html>
這個案例是正常的情況,但是你們是否有注意到其實我這裏的高度是設置再v-enter上面的?因爲當我們設置再v-enter下面的時候就會出現問題?其實答案很簡單就是樣式發生了覆蓋,導致高度一直都是156px還怎麼過渡對吧,覆蓋是根據css文件中樣式書寫的順序,不是HTML上的順序,大家可以去放下去試一下
<style>
/* .box p{
margin: 0;
height: 156px;
border: 1px solid saddlebrown;
} */
.bounce-enter-active,.bounce-leave-active {
transition: all 1s ease;
}
.bounce-leave,.bounce-enter-to{
height: 156px;
}
.bounce-enter,.bounce-leave-to {
height: 0;
color: chartreuse;
}
.box{
border: 1px solid saddlebrown;
background-color: brown;
height: 156px;
}
</style>
也可以去打開F12去看樣式中有被下劃線,因爲替代而被下劃的樣式;
4.v-if和v-show的區別
再vue中的javaScriot鉤子函數(enter等下面的那些)監聽的是瀏覽器渲染樹中結構,所以v-if和v-show的區別其實是
v-if:先生成DOM樹瀏覽器渲染樹中的那個結構也是新生成的;
v-show:是修改了DOM樹,瀏覽器中的渲染樹是去更新渲染樹
那麼注意區分的原因是什麼,當我們去控制一個div的時候如果div中的數據有用JavaScriot鉤子函數(enter等下面的那些)監聽
的時候很有可能v-if他會再第一次監聽不到,因爲再第一次生成DOM樹的時候連第一次的數據也一同傳給了渲染樹,在vue中,數據和DOM是異步同時執行,但是DOM要等裏面的數據好了纔算OK,所以可能再第一次監聽那個div中的數據跟新的時候就監聽不到,因爲第一次我們是希望監聽的是沒數據到數據的添加的這個事件;而用v-show那麼div在DOM樹上就一直存在,那麼在瀏覽器渲染樹上也就一次存在,當第一次數據改變我們就只是數據改變就OK了
解決問題:那麼我們如果解決問題呢?我們只需要讓DOM樹生成的過程中不要代第一次的數據,讓那個div中改變數據的行爲代碼在下一幀執行,就可以了,那麼DOM樹就是先有了那個DIV,在是在下一幀添加數據就和v-show的表現形式一樣了,那麼這個再下一幀的方法就是$nextTick();
動畫
爲什麼這裏不用謝v-enter呢? 我們想一下其實我們動畫裏面是包含了開始狀態和結束狀態的,我們需要的只是執行那個動畫,不用想過渡一樣定義過渡的開始和結束值
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Vue中css動畫的原理</title>
<script src="./node_modules/vue/dist/vue.js"></script>
<style>
@keyframes bounce {
0% {
transform: scale(0);
}
50% {
transform: scale(1.5);
}
100% {
transform: scale(1);
}
}
/* .fade-enter-active和.fade-leave-active代表一直都在的那個時間點 */
.fade-enter-active {
transform-origin: left center;
/* 這裏寫這個因爲div太寬了 */
animation: bounce 1s;
}
.fade-leave-active {
transform-origin: left center;
animation: bounce 1s reverse;
}
</style>
</head>
<body>
<div id="root">
<transition name="fade">
<div v-if="show">hello world</div>
</transition>
<button @click="click">切換</button>
</div>
<script>
var root = new Vue({
el: '#root',
data: {
show: true
},
methods: {
click: function () {
this.show = !this.show;
}
}
})
</script>
</body>
</html>
這裏你會發現動畫沒寫v-enter和v-leave-to爲什麼呢?
因爲他是動畫啊它不需要像過濾一樣有初始和結束的差別來判斷,他只需要知道什麼時候執行v-enter-active 和v-leave-active
再執行裏面的語句就可以了
JavaScript鉤子函數
除了用CSS過渡的動畫來實現vue的組件過渡,還可以用JavaScript的鉤子函數來實現,在鉤子函數中直接操作DOM。我們可以在屬性中聲明以下鉤子:
<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) {
// ...
},
// 設置過渡進入完成時的組件狀態
enter: function (el, done) {
// ...
done()
},
// 設置過渡進入完成之後的組件狀態
afterEnter: function (el) {
// ...
},
enterCancelled: function (el) {
// ...
},
// 過渡離開
// 設置過渡離開之前的組件狀態
beforeLeave: function (el) {
// ...
},
// 設置過渡離開完成時地組件狀態
leave: function (el, done) {
// ...
done()
},
// 設置過渡離開完成之後的組件狀態
afterLeave: function (el) {
// ...
},
// leaveCancelled 只用於 v-show 中
leaveCancelled: function (el) {
// ...
}
}