過渡
Vue提供兩個內建元件,可以幫助處理響應狀態變化時的過渡和動畫
<Transition>在元素或元件進入和離開DOM時應用動畫。這在本頁上有介紹。<TransitionGroup>在元素或元件被插入到、從v-for列表中移除或在其內部移動時應用動畫。這將在下一章中介紹。
除了這兩個元件之外,我們還可以使用其他技術,如切換CSS類或透過樣式繫結實現狀態驅動的動畫,在Vue中應用動畫。這些額外的技術將在動畫技巧章節中介紹。
<Transition> 元件
<Transition> 是一個內建元件:這意味著它可以在任何元件的模板中使用,而無需註冊。它可以用於對其預設插槽傳入的元素或元件應用進入和離開動畫。進入或離開可以由以下之一觸發
- 透過
v-if進行條件渲染 - 透過
v-show進行條件顯示 - 透過
<component>特殊元素動態切換元件 - 更改特殊的
key屬性
這是一個最基本使用示例
模板
<button @click="show = !show">Toggle</button>
<Transition>
<p v-if="show">hello</p>
</Transition>CSS
/* we will explain what these classes do next! */
.v-enter-active,
.v-leave-active {
transition: opacity 0.5s ease;
}
.v-enter-from,
.v-leave-to {
opacity: 0;
}hello
提示
<Transition> 只支援單個元素或元件作為其插槽內容。如果內容是元件,該元件也必須只有一個根元素。
當 <Transition> 元件中的元素被插入或移除時,會發生以下情況
Vue會自動檢查目標元素是否應用了CSS過渡或動畫。如果應用了,將新增/移除一系列CSS過渡類,時機適當。
如果有監聽器監聽JavaScript鉤子,則這些鉤子將在適當的時機被呼叫。
如果沒有檢測到CSS過渡/動畫,並且沒有提供JavaScript鉤子,則插入和/或刪除的DOM操作將在瀏覽器的下一個動畫幀上執行。
基於CSS的過渡
過渡類
共有六個類用於進入/離開過渡。

v-enter-from:進入的起始狀態。在元素插入前新增,元素插入後一幀移除。v-enter-active:進入的活躍狀態。在整個進入階段應用。在元素插入前新增,在過渡/動畫完成後移除。這個類可以用來定義進入過渡的持續時間、延遲和緩動曲線。v-enter-to:進入的結束狀態。在元素插入後一幀新增(同時移除v-enter-from),在過渡/動畫完成後移除。v-leave-from:離開的起始狀態。在離開過渡觸發時立即新增,一幀後移除。v-leave-active:離開的活躍狀態。在整個離開階段應用。在離開過渡觸發時立即新增,在過渡/動畫完成後移除。這個類可以用來定義離開過渡的持續時間、延遲和緩動曲線。v-leave-to:離開的結束狀態。在離開過渡觸發後一幀新增(同時移除v-leave-from),在過渡/動畫完成後移除。
v-enter-active和v-leave-active允許我們為進入/離開過渡指定不同的緩動曲線,以下章節將給出一個示例。
命名過渡
可以透過name屬性命名一個過渡。
模板
<Transition name="fade">
...
</Transition>對於命名過渡,其過渡類將以其名稱為字首而不是v。例如,上述過渡應用的是fade-enter-active而不是v-enter-active。fade過渡的CSS應如下所示
CSS
.fade-enter-active,
.fade-leave-active {
transition: opacity 0.5s ease;
}
.fade-enter-from,
.fade-leave-to {
opacity: 0;
}CSS過渡
<Transition>通常與原生CSS過渡結合使用,如上述基本示例所示。CSS的transition屬性是一個簡寫,允許我們指定過渡的多個方面,包括應動畫化的屬性、過渡的持續時間以及緩動曲線。
以下是一個更高階的示例,它轉換多個屬性,為進入和離開指定不同的持續時間緩動曲線。
模板
<Transition name="slide-fade">
<p v-if="show">hello</p>
</Transition>CSS
/*
Enter and leave animations can use different
durations and timing functions.
*/
.slide-fade-enter-active {
transition: all 0.3s ease-out;
}
.slide-fade-leave-active {
transition: all 0.8s cubic-bezier(1, 0.5, 0.8, 1);
}
.slide-fade-enter-from,
.slide-fade-leave-to {
transform: translateX(20px);
opacity: 0;
}hello
CSS動畫
原生CSS動畫的應用方式與CSS過渡相同,區別在於*-enter-from不是在元素插入後立即移除,而是在animationend事件發生時移除。
對於大多數CSS動畫,我們可以在*-enter-active和*-leave-active類下簡單宣告它們。以下是一個示例
模板
<Transition name="bounce">
<p v-if="show" style="text-align: center;">
Hello here is some bouncy text!
</p>
</Transition>CSS
.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.25);
}
100% {
transform: scale(1);
}
}你好,這裡有一些彈跳文字!
自定義過渡類
您還可以透過向<Transition>傳遞以下屬性來指定自定義過渡類
enter-from-classenter-active-classenter-to-classleave-from-classleave-active-classleave-to-class
這些將覆蓋常規類名。當您想將Vue的過渡系統與現有的CSS動畫庫(如Animate.css)結合使用時,這特別有用。
模板
<!-- assuming Animate.css is included on the page -->
<Transition
name="custom-classes"
enter-active-class="animate__animated animate__tada"
leave-active-class="animate__animated animate__bounceOutRight"
>
<p v-if="show">hello</p>
</Transition>同時使用過渡和動畫
Vue需要附加事件監聽器以瞭解何時過渡結束。它可以是被應用的CSS規則的型別決定的transitionend或animationend。如果您只使用其中之一,Vue可以自動檢測正確的型別。
但是,在某些情況下,您可能希望在同一個元素上同時使用這兩種效果,例如,當Vue觸發CSS動畫時,在懸停時新增CSS過渡效果。在這些情況下,您必須透過傳遞具有值為animation或transition的type屬性來顯式宣告Vue應該關注的型別。
模板
<Transition type="animation">...</Transition>巢狀過渡和顯式過渡持續時間
儘管過渡類只應用於<Transition>中的直接子元素,但我們可以使用巢狀CSS選擇器來過渡巢狀元素
模板
<Transition name="nested">
<div v-if="show" class="outer">
<div class="inner">
Hello
</div>
</div>
</Transition>CSS
/* rules that target nested elements */
.nested-enter-active .inner,
.nested-leave-active .inner {
transition: all 0.3s ease-in-out;
}
.nested-enter-from .inner,
.nested-leave-to .inner {
transform: translateX(30px);
opacity: 0;
}
/* ... other necessary CSS omitted */我們甚至可以在進入時為巢狀元素新增過渡延遲,這會建立一個交錯進入動畫序列
CSS
/* delay enter of nested element for staggered effect */
.nested-enter-active .inner {
transition-delay: 0.25s;
}然而,這會引發一個小問題。預設情況下,<Transition>元件嘗試透過監聽根過渡元素的第一個transitionend或animationend事件來自動確定何時過渡完成。對於巢狀過渡,所需的操作應該是等待所有內部元素的過渡都完成。
在這種情況下,您可以使用<transition>元件上的duration屬性(以毫秒為單位)指定顯式過渡持續時間。總持續時間應等於延遲加上內部元素的過渡持續時間
模板
<Transition :duration="550">...</Transition>你好
如果需要,您還可以使用物件指定進入和離開的持續時間
模板
<Transition :duration="{ enter: 500, leave: 800 }">...</Transition>效能考慮因素
您可能已經注意到上述動畫大多使用transform和opacity等屬性。這些屬性易於動畫化,因為
它們在動畫期間不影響文件佈局,因此它們不會在每一幀上觸發昂貴的CSS佈局計算。
大多數現代瀏覽器在動畫
transform時可以利用GPU硬體加速。
相比之下,height或margin等屬性將觸發CSS佈局,因此它們動畫化起來成本更高,應謹慎使用。
JavaScript鉤子
您可以透過監聽<Transition>元件上的事件來使用JavaScript掛鉤到過渡過程
html
<Transition
@before-enter="onBeforeEnter"
@enter="onEnter"
@after-enter="onAfterEnter"
@enter-cancelled="onEnterCancelled"
@before-leave="onBeforeLeave"
@leave="onLeave"
@after-leave="onAfterLeave"
@leave-cancelled="onLeaveCancelled"
>
<!-- ... -->
</Transition>js
// called before the element is inserted into the DOM.
// use this to set the "enter-from" state of the element
function onBeforeEnter(el) {}
// called one frame after the element is inserted.
// use this to start the entering animation.
function onEnter(el, done) {
// call the done callback to indicate transition end
// optional if used in combination with CSS
done()
}
// called when the enter transition has finished.
function onAfterEnter(el) {}
// called when the enter transition is cancelled before completion.
function onEnterCancelled(el) {}
// called before the leave hook.
// Most of the time, you should just use the leave hook
function onBeforeLeave(el) {}
// called when the leave transition starts.
// use this to start the leaving animation.
function onLeave(el, done) {
// call the done callback to indicate transition end
// optional if used in combination with CSS
done()
}
// called when the leave transition has finished and the
// element has been removed from the DOM.
function onAfterLeave(el) {}
// only available with v-show transitions
function onLeaveCancelled(el) {}這些鉤子可以與CSS過渡/動畫結合使用,或者單獨使用。
在使用僅JavaScript的過渡時,通常新增:css="false"屬性是個好主意。這會明確告訴Vue跳過自動CSS過渡檢測。除了效能略高外,這還可以防止CSS規則意外干擾過渡。
模板
<Transition
...
:css="false"
>
...
</Transition>使用:css="false"時,我們也完全負責控制過渡何時結束。在這種情況下,對於@enter和@leave鉤子,需要提供done回撥。否則,鉤子將同步呼叫,並且過渡將立即完成。
以下是一個使用GSAP庫執行動畫的示例。當然,您可以使用任何其他動畫庫,例如Anime.js或Motion One
可重用過渡
可以透過Vue的元件系統重用過渡。要建立可重用的過渡,我們可以建立一個元件,該元件包裝了<Transition>元件,並將槽內容傳遞下去。
vue
<!-- MyTransition.vue -->
<script>
// JavaScript hooks logic...
</script>
<template>
<!-- wrap the built-in Transition component -->
<Transition
name="my-transition"
@enter="onEnter"
@leave="onLeave">
<slot></slot> <!-- pass down slot content -->
</Transition>
</template>
<style>
/*
Necessary CSS...
Note: avoid using <style scoped> here since it
does not apply to slot content.
*/
</style>現在MyTransition可以像內建版本一樣匯入和使用。
模板
<MyTransition>
<div v-if="show">Hello</div>
</MyTransition>出現在過渡
如果您還希望在節點的初始渲染時應用過渡,可以新增appear屬性。
模板
<Transition appear>
...
</Transition>元素間的過渡
除了使用v-if / v-show切換元素外,我們還可以使用v-if / v-else / v-else-if在兩個元素之間進行過渡,只要我們確保在任何給定時刻只顯示一個元素。
模板
<Transition>
<button v-if="docState === 'saved'">Edit</button>
<button v-else-if="docState === 'edited'">Save</button>
<button v-else-if="docState === 'editing'">Cancel</button>
</Transition>點選迴圈狀態
過渡模式
在上一個示例中,進入和離開元素同時進行動畫,我們必須將它們設定為position: absolute以避免在DOM中同時存在兩個元素時的佈局問題。
但是,在某些情況下這不是一個選項,或者根本不是我們想要的操作。我們可能希望先對離開元素進行動畫,然後只有在離開動畫完成後才將進入元素插入。手動編排這樣的動畫將非常複雜——幸運的是,我們可以透過傳遞一個mode屬性給<Transition>來啟用這種行為。
模板
<Transition mode="out-in">
...
</Transition>以下是之前示例中帶有mode="out-in"的演示。
點選迴圈狀態
<Transition>還支援mode="in-out",儘管它使用得較少。
元件間的過渡
<Transition>也可以用於動態元件周圍。
模板
<Transition name="fade" mode="out-in">
<component :is="activeComponent"></component>
</Transition>元件A
動態過渡
<Transition>的name等屬性也可以是動態的!這允許我們根據狀態變化動態應用不同的過渡。
模板
<Transition :name="transitionName">
<!-- ... -->
</Transition>當您使用Vue的過渡類約定定義了CSS過渡/動畫,並希望在這些過渡之間切換時,這可能會很有用。
您還可以根據元件的當前狀態,在JavaScript過渡鉤子中應用不同的行為。最後,建立動態過渡的終極方法是使用可複用過渡元件,這些元件接受props來改變要使用的過渡的性質。這可能聽起來有點陳詞濫調,但真正的限制實際上只是您的想象力。
具有鍵屬性(Key Attribute)的過渡
有時您需要強制重新渲染DOM元素,以便過渡發生。
以這個計數器元件為例
vue
<script setup>
import { ref } from 'vue';
const count = ref(0);
setInterval(() => count.value++, 1000);
</script>
<template>
<Transition>
<span :key="count">{{ count }}</span>
</Transition>
</template>如果我們排除了key屬性,則只會更新文字節點,因此不會發生過渡。然而,當存在key屬性時,Vue知道每當count發生變化時,都會建立一個新的span元素,因此Transition元件有兩個不同的元素可以過渡。
相關