一. vue的過(guò)渡與動(dòng)畫(huà)
Vue 在插入攻冷、更新或者移除 DOM 時(shí)具帮,提供多種不同方式的應(yīng)用過(guò)渡效果。過(guò)渡效果的應(yīng)用可以通過(guò)不同方式實(shí)現(xiàn):
- 在CSS過(guò)渡和動(dòng)畫(huà)中自動(dòng)應(yīng)用class
- 在過(guò)渡鉤子函數(shù)中使用JavaScript直接操作dom
- 配合第三方css動(dòng)畫(huà)庫(kù):Animate.css 或者第三方j(luò)avascript動(dòng)畫(huà)庫(kù):Velocity
上面三種方式其實(shí)主要就是兩種:一個(gè)是利用CSS過(guò)渡或者動(dòng)畫(huà)券时,另一個(gè)是利用JavaScript鉤子函數(shù)懦尝。
二. 如何應(yīng)用過(guò)渡與動(dòng)畫(huà)
下面從進(jìn)入離開(kāi)過(guò)渡以及列表過(guò)渡兩大方向,概述vue如何為元素添加過(guò)渡效果浩考。
2-1. 單元素/組件進(jìn)入離開(kāi)過(guò)渡
1. css過(guò)渡
vue提供了transition
封裝組件夹孔,在以下情況下為任何單元素以及組件添加進(jìn)入/離開(kāi)過(guò)渡。
- 條件渲染
v-if
/ 條件展示v-show
- 動(dòng)態(tài)組件
- 組件根節(jié)點(diǎn)
例子如下:
<div>
<button @click="show = !show">切換</button>
<transition name="fade">
<p v-if="show">看我顯示隱藏!!!</p>
</transition>
</div>
.fade-enter-active {
transition: all 0.5s ease;
}
.fade-leave-active {
transition: all 0.9s cubic-bezier(1, 0.5, 0.8, 1);
}
.fade-enter,
.fade-leave-to {
opacity: 0;
transform: translateX(20px);
}
2. css動(dòng)畫(huà)
CSS 動(dòng)畫(huà)用法同 CSS 過(guò)渡析孽,區(qū)別是在動(dòng)畫(huà)中 v-enter
類名在節(jié)點(diǎn)插入 DOM 后不會(huì)立即刪除搭伤,而是在 animationend
事件觸發(fā)時(shí)刪除。
<transition name="bounce">
<div style="width:300px;height:400px;" v-if="show">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris facilisis enim libero, at lacinia diam fermentum id.
Pellentesque habitant morbi tristique senectus et netus.
</div>
</transition>
3. javascript鉤子函數(shù)
可以在<transition>
組件上聲明JavaScript鉤子函數(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"
>
</transition>
methods: {
// ---- 進(jìn)入中 ------
beforeEnter: function (el) {
},
// 當(dāng)與 CSS 結(jié)合使用時(shí)
// 回調(diào)函數(shù) done 是可選的
enter: function (el, done) {
// ...
done()
},
afterEnter: function (el) {
// ...
},
enterCancelled: function (el) {
// ...
}
}
4. 過(guò)渡的類名
進(jìn)入/離開(kāi)過(guò)渡的類名
-
v-enter
:定義過(guò)渡的開(kāi)始狀態(tài)怜俐。在元素插入之前生效,在元素被插入的下一幀移除 -
v-enter-active
:定義過(guò)渡生效時(shí)候的狀態(tài)邓尤。在整個(gè)進(jìn)入過(guò)渡的階段中應(yīng)用拍鲤。這個(gè)類可以被用來(lái)定義進(jìn)入過(guò)渡的過(guò)程時(shí)間贴谎,延遲和曲線函數(shù) -
v-enter-to
:定義過(guò)渡的結(jié)束狀態(tài)。在元素被插入之后下一幀生效季稳,在過(guò)渡/動(dòng)畫(huà)完成之后移除擅这。 -
v-leave
:定義離開(kāi)過(guò)渡的開(kāi)始狀態(tài)。在離開(kāi)過(guò)渡被觸發(fā)時(shí)立刻生效景鼠,下一幀被移除仲翎。 -
v-leave-active
:定義離開(kāi)過(guò)渡生效時(shí)的狀態(tài)。在整個(gè)離開(kāi)過(guò)渡的階段中應(yīng)用铛漓。 -
v-leave-to
:定義離開(kāi)過(guò)渡的結(jié)束狀態(tài)溯香。
- 在
<transition name="fade">
組件中,通過(guò)name
屬性浓恶,定義過(guò)渡的類名逐哈;如果沒(méi)有命名,則使用默認(rèn)的v-
為類名的前綴问顷,例如:v-enter
... - 我們還可以自定義過(guò)渡的類名:
enter-class
,enter-active-class
,enter-to-class
,leave-class
,leave-active-class
,leave-to-class
。它們的優(yōu)先級(jí)高于普通的類名禀梳。
代碼如下:
<button @click="show = !show">切換</button>
<transition
name="custom-classes-transition"
enter-active-class="animated tada"
leave-active-class="animated bounceOutRight"
>
<p v-if="show">看我杜窄!</p>
</transition>
.bounce-enter-active {
animation: bounce-in 0.5s;
}
.bounce-leave-active {
animation: bounce-in 0.5s reverse;
}
@keyframes bounce-in {
0% {
transform: scale(0);
}
50% {
transform: scale(1.5);
}
0% {
transform: scale(1);
}
}
5. 同時(shí)使用css過(guò)渡/動(dòng)畫(huà)
使用 type
特性并設(shè)置 animation
或 transition
來(lái)明確聲明你需要 Vue 監(jiān)聽(tīng)的類型。
6. 過(guò)渡持續(xù)事件
用 <transition>
組件上的 duration
屬性定制一個(gè)顯性的過(guò)渡持續(xù)時(shí)間 (以毫秒計(jì)):
<transition :duration="1000">...</transition>
<transition :duration="{ enter: 500, leave: 800 }">...</transition>
7. 初始渲染的過(guò)渡
使用apear
特性設(shè)置節(jié)點(diǎn)在初始渲染的過(guò)渡算途。與進(jìn)入和離開(kāi)一樣塞耕,可以自定義css類名以及javascript鉤子函數(shù)。
<transition
appear
appear-class="custom-appear-class"
appear-to-class="custom-appear-to-class"
appear-active-class="custom-appear-active-class"
>
<!-- ... -->
</transition>
<transition
appear
v-on:before-appear="customBeforeAppearHook"
v-on:appear="customAppearHook"
v-on:after-appear="customAfterAppearHook"
v-on:appear-cancelled="customAppearCancelledHook"
>
<!-- ... -->
</transition>
8. 多個(gè)元素/組件 過(guò)渡
-
<transition>
內(nèi)如果是原生標(biāo)簽嘴瓤,可以使用v-if
/v-else
扫外。
注意事項(xiàng):當(dāng)有相同標(biāo)簽名的元素切換時(shí),需要給在 <transition> 組件中的多個(gè)元素設(shè)置 key 是一個(gè)更好的實(shí)踐廓脆。
- 多組件過(guò)渡筛谚,不需要提供
key
,只需要使用動(dòng)態(tài)組件
停忿。
<transition>
<button v-if="isEditing" key="save"> Save </button>
<button v-else key="edit"> Edit </button>
</transition>
9. vue 提供的過(guò)渡模式
-
in-out
:新元素先進(jìn)行過(guò)渡驾讲,完成之后當(dāng)前元素過(guò)渡離開(kāi)。 -
out-in
:當(dāng)前元素先進(jìn)行過(guò)渡席赂,完成之后新元素過(guò)渡進(jìn)入吮铭。
2-2 列表過(guò)渡
在使用v-for
同時(shí)渲染整個(gè)列表的時(shí)候,可以使用<transition-group>
組件颅停。其與<transition>
組件的區(qū)別:
- 以真實(shí)元素呈現(xiàn)谓晌,默認(rèn)是
<span>
,可以通過(guò)tag
屬性更換其他元素。 -
過(guò)渡模式
不可用 - 內(nèi)部元素總是需要提供key屬性值
列表的三種過(guò)渡模式:
- 列表的進(jìn)入/離開(kāi)過(guò)渡
- 列表的排序過(guò)渡
- 列表的交錯(cuò)過(guò)渡
代碼匯總?cè)缦拢?/p>
<!-- 1. 列表交錯(cuò)過(guò)渡 -->
<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>
<!-- 2. 列表進(jìn)入-離開(kāi)過(guò)渡 -->
<button @click="add">add</button>
<button @click="remove">remove</button>
<transition-group tag="p" name="list">
<span v-for="item in items" :key="item" class="list-item">{{item}}</span>
</transition-group>
<!-- 3. 列表排序過(guò)渡 -->
<button @click="Shuffle">Shuffle</button>
<transition-group tag="ul" name="flip-list">
<li v-for="item in items" :key="item" class="list-item">{{item}}</li>
</transition-group>
export default {
name: "listTransition",
data() {
return {
list: [
{ msg: "Bruce Lee" },
{ msg: "Jackie Chan" },
{ msg: "Chuck Norris" },
{ msg: "Jet Li" },
{ msg: "Kung Fury" }
],
items: [1, 2, 3, 4, 5, 6, 7, 8, 9],
nextNum: 10
};
},
computed: {
computedList: function() {
var vm = this;
return this.list.filter(function(item) {
return item.msg.toLowerCase().indexOf(vm.query.toLowerCase()) !== -1;
});
}
},
methods: {
// 1. 當(dāng)只用 JavaScript 過(guò)渡的時(shí)候癞揉,在 enter 和 leave 中必須使用 done 進(jìn)行回調(diào)纸肉。否則溺欧,它們將被同步調(diào)用,過(guò)渡會(huì)立即完成毁靶。
// 2. 推薦對(duì)于僅使用 JavaScript 過(guò)渡的元素添加 v-bind:css="false"胧奔,Vue 會(huì)跳過(guò) CSS 的檢測(cè)。這也可以避免過(guò)渡過(guò)程中 CSS 的影響预吆。
// appear 特性設(shè)置節(jié)點(diǎn)在初始渲染的過(guò)渡
// <transition-group>組件 用于列表進(jìn)入離開(kāi)過(guò)渡 / 排序過(guò)渡(v-move)
// 自定義類名前綴:(1)name屬性 (2)move-class/enter-class...屬性手動(dòng)設(shè)置
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);
},
// 2. 列表進(jìn)入-離開(kāi)過(guò)渡
randomIndex: function() {
return Math.floor(Math.random() * this.items.length);
},
add() {
this.items.splice(this.randomIndex(), 0, this.nextNum++);
},
remove() {
this.items.splice(this.randomIndex(), 1);
},
// 3. 列表-排序過(guò)渡
Shuffle() {
this.items = _.shuffle(this.items);
}
}
};
/* 2. 進(jìn)入離開(kāi)過(guò)渡-列表 */
.list-item {
margin-right: 20px;
display: inline-block;
}
.list-enter-active,
.list-leave-active {
transition: all 1s;
}
.list-enter,
.list-leave-to {
opacity: 0;
transform: translateY(30px);
}
/* 排序 */
.flip-list-move{
transition: transform 1s;
}