Transition 元件通常有三類用法:CSS 過渡,CSS 動畫和 JavaScript 鉤子。我們分別用幾個示例來說明,這裡我希望你可以敲程式碼執行感受一下。
首先來看 CSS 過渡:
<template>
<div class="app">
<button @click="show = !show">
Toggle render
</button>
<transition name="fade">
<p v-if="show">hello</p>
</transition>
</div>
</template>
<script>
export default {
data() {
return {
show: true
}
}
}
</script>
<style>
.fade-enter-active,
.fade-leave-active {
transition: opacity 0.5s ease;
}
.fade-enter-from,
.fade-leave-to {
opacity: 0;
}
</style>
CSS 過渡主要定義了一些過渡的 CSS 樣式,當我們點選按鈕切換文字顯隱的時候,就會應用這些 CSS 樣式,實現過渡效果。
接著來看 CSS 動畫:
<template>
<div class="app">
<button @click="show = !show">Toggle show</button>
<transition name="bounce">
<p v-if="show">Vue is an awesome front-end MVVM framework. We can use it to build multiple apps.</p>
</transition>
</div>
</template>
<script>
export default {
data() {
return {
show: true
}
}
}
</script>
<style>
.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);
}
100% {
transform: scale(1);
}
}
</style>
和 CSS 過渡類似,CSS 動畫主要定義了一些動畫的 CSS 樣式,當我們去點選按鈕切換文字顯隱的時候,就會應用這些 CSS 樣式,實現動畫效果。
最後,是 JavaScript 鉤子:
<template>
<div class="app">
<button @click="show = !show">
Toggle render
</button>
<transition
@before-enter="beforeEnter"
@enter="enter"
@before-leave="beforeLeave"
@leave="leave"
css="false"
>
<p v-if="show">hello</p>
</transition>
</div>
</template>
<script>
export default {
data() {
return {
show: true
}
},
methods: {
beforeEnter(el) {
el.style.opacity = 0
el.style.transition = 'opacity 0.5s ease'
},
enter(el) {
this.$el.offsetHeight
el.style.opacity = 1
},
beforeLeave(el) {
el.style.opacity = 1
},
leave(el) {
el.style.transition = 'opacity 0.5s ease'
el.style.opacity = 0
}
}
}
</script>
Transition 元件也允許在一個過渡元件中定義它過渡生命週期的 JavaScript 鉤子函式,我們可以在這些鉤子函式中編寫 JavaScript 操作 DOM 來實現過渡動畫效果。
Transition 元件的核心思想
透過前面三個示例,我們不難發現都是在點選按鈕時,透過修改 v-if 的條件值來觸發過渡動畫的。
其實 Transition 元件過渡動畫的觸發條件有以下四點:
- 條件渲染 (使用 v-if);
- 條件展示 (使用 v-show);
- 動態元件;
- 元件根節點。
所以你只能在上述四種情況中使用 Transition 元件,在進入/離開過渡的時候會有 6 個 class 切換。
- v-enter-from:定義進入過渡的開始狀態。在元素被插入之前生效,在元素被插入之後的下一幀移除。
- v-enter-active:定義進入過渡生效時的狀態。在整個進入過渡的階段中應用,在元素被插入之前生效,在過渡動畫完成之後移除。這個類可以被用來定義進入過渡的過程時間,延遲和曲線函式。
- v-enter-to:定義進入過渡的結束狀態。在元素被插入之後下一幀生效 (與此同時 v-enter-from 被移除),在過渡動畫完成之後移除。
- v-leave-from:定義離開過渡的開始狀態。在離開過渡被觸發時立刻生效,下一幀被移除。
- v-leave-active:定義離開過渡生效時的狀態。在整個離開過渡的階段中應用,在離開過渡被觸發時立刻生效,在過渡動畫完成之後移除。這個類可以被用來定義離開過渡的過程時間,延遲和曲線函式。
- v-leave-to:定義離開過渡的結束狀態。在離開過渡被觸發之後下一幀生效 (與此同時 v-leave-from 被刪除),在過渡動畫完成之後移除。
其實說白了 Transition 元件的核心思想就是,Transition 包裹的元素插入刪除時,在適當的時機插入這些 CSS 樣式,而這些 CSS 的實現則決定了元素的過渡動畫。
大致瞭解了 Transition 元件的用法和核心思想後,接下來我們就來探究 Transition 元件的實現原理。
Transition 元件的實現原理
為了方便你的理解,我們還是結合示例來分析:
<template>
<div class="app">
<button @click="show = !show">
Toggle render
</button>
<transition name="fade">
<p v-if="show">hello</p>
</transition>
</div>
</template>
先來看模板編譯後生成的 render 函式:
import { createVNode as _createVNode, openBlock as _openBlock, createBlock as _createBlock, createCommentVNode as _createCommentVNode, Transition as _Transition, withCtx as _withCtx } from "vue"
export function render(_ctx, _cache, $props, $setup, $data, $options) {
return (_openBlock(), _createBlock("template", null, [
_createVNode("div", { class: "app" }, [
_createVNode("button", {
onClick: $event => (_ctx.show = !_ctx.show)
}, " Toggle render ", 8 /* PROPS */, ["onClick"]),
_createVNode(_Transition, { name: "fade" }, {
default: _withCtx(() => [
(_ctx.show)
? (_openBlock(), _createBlock("p", { key: 0 }, "hello"))
: _createCommentVNode("v-if", true)
]),
_: 1
})
])
]))
}
對於 Transition 元件部分,生成的 render 函式主要建立了Transition 元件 vnode,並且有一個預設插槽。
如果你仔細研究transition的實現你會發現,Transition 元件是在 BaseTransition 的基礎上封裝的高階函式式元件。由於整個 Transition 的實現程式碼較多,我就挑重點,為你講清楚整體的實現思路。
Transition 元件的實現其實可以分成元件的渲染、鉤子函式的執行、模式的應用三個部分看待。
其中最重要的就是元件的渲染:我們應當重點看 setup 函式部分的邏輯。
Transition 元件和前面學習的 KeepAlive 元件一樣,是一個抽象元件,元件本身不渲染任何實體節點,只渲染第一個子元素節點。
注意,Transition 元件內部只能巢狀一個子元素節點,如果有多個節點需要用 TransitionGroup 元件。
如果 Transition 元件內部巢狀的是 KeepAlive 元件,那麼它會繼續查詢 KeepAlive 元件巢狀的第一個子元素節點,來作為渲染的元素節點。
如果 Transition 元件內部沒有巢狀任何子節點,那麼它會渲染空的註釋節點。
在渲染的過程中,Transition 元件還會透過 resolveTransitionHooks 去定義元件建立和刪除階段的鉤子函式物件,然後再透過 setTransitionHooks函式去把這個鉤子函式物件設定到 vnode.transition 上。
渲染過程中,還會判斷這是否是一次更新渲染,如果是會對不同的模式執行不同的處理邏輯,我會在後續介紹模式的應用時詳細說明。
以上就是 Transition 元件渲染做的事情,你需要記住的是Transition 渲染的是元件巢狀的第一個子元素節點!