# transition 元件 >[竹白記事本](https://chupainotebook.bloggi.co/) [Vue Transition|目錄](https://hackmd.io/@chupai/HkQQA8c4U) ###### tags: `Vue Transition` `竹白的 Vue.js 學習筆記` ## transition 元件 Vue 提供了 `transition` 的封裝元件,在下列情形中,可以給任何元素和元件添加進入/離開的轉場效果: - 元素或元件初始渲染時 - 元素或元件顯示/隱藏時(使用 `v-if` 或 `v-show`) - 元素或元件切換時 先看一個簡單的基本範例: ```htmlmixed <button v-on:click="show = !show">Toggle</button> <transition> <div class="box" v-if="show">2</div> </transition> ``` ```javascript data: { show: true, }, ``` ```css .v-enter, .v-leave-to { opacity: 0; } .v-leave, .v-enter-to { opacity: 1; } .v-enter-active, .v-leave-active { transition: opacity 1s; } ``` 當我們使用 `transition` 元件將元素包住,Vue 會做以下處理: 1. 自動偵測目標元素是否應用 CSS `transition/animation` 如果是,在恰當的時機添加/刪除 CSS 類別名稱。 2. 如果 `transition` 元件提供了 JavaScript 鉤子函式,這些鉤子函式將在恰當的時機被呼叫。 3. 如果沒有找到 JavaScript 鉤子並且也沒有檢測到 CSS `transition/animation`,DOM 操作 (插入/刪除) 在下一幀中立即執行。 <iframe height="260" style="width: 100%;" scrolling="no" title="Vue CSS 轉場 基本範例" src="https://codepen.io/CHUPAIWANG/embed/eYmzyQN?height=265&theme-id=default&default-tab=result" frameborder="no" allowtransparency="true" allowfullscreen="true"> See the Pen <a href='https://codepen.io/CHUPAIWANG/pen/eYmzyQN'>Vue CSS 轉場 基本範例</a> by CHUPAIWANG (<a href='https://codepen.io/CHUPAIWANG'>@CHUPAIWANG</a>) on <a href='https://codepen.io'>CodePen</a>. </iframe> ## CSS 轉場的類別名稱 `transition` 元件共提供了,六種類別名稱提供切換。 ![](https://i.imgur.com/mkKyGHV.png) 進場: - `v-enter`:定義進場的開始狀態。 - 在元素被插入之前生效,插入之後的下一幀被移除 - `v-enter-active`:定義進場生效時的狀態,在整個進場的階段中應用。 - 在元素被插入之前生效,在 `transition/animation` 完成之後移除 - 可用來定義進場的過程時間,延遲和曲線函數 - `v-enter-to`:**2.1.8版及以上** 定義進場的結束狀態。 - 在元素被插入之後下一幀生效(與此同時 `v-enter` 被移除),在 `transition/animation` 完成之後移除 離場: - `v-leave`:定義離場的開始狀態。 - 在離場被觸發時立刻生效,下一幀被移除 - `v-leave-active`:定義離場生效時的狀態,在整個離場的階段中應用。 - 在離場被觸發時立刻生效,在 `transition/animation` 完成之後移除 - 這個類可以被用來定義離場的過程時間,延遲和曲線函數 - `v-leave-to`:**2.1.8版及以上** 定義離場的結束狀態。 - 在離開轉場被觸發之後下一幀生效(與此同時 `v-leave` 被移除),在 `transition/animation` 完成之後移除 通常會設定 `v-enter` 與 `v-leave-active` 相同的效果、`v-leave` 與 `v-enter-to` 相同的效果,達到同尾相接形成一個循環,而 `v-enter-to` 與 `v-leave-to` 會用來設定轉場時間或動畫。 :::info `enter-to` 預設 `opacity: 1`、`transform: none`,所以不一定要設定。 ::: ### 1. CSS `transition` `transition` 元件預設使用上述 `v-` 前綴的類別名稱。請參考一開始基本範例。 因為不可能只用一種動態效果,因此使用自訂義的前綴,需要加上 `name` 特性,舉例來說,`<transition name="fade">`,套用的那麼類別名稱的前綴就會是 `fade-enter`。 ```htmlmixed <button v-on:click="show = !show"> Toggle </button> <transition name="fade"> <div class="box" v-if="show"></div> </transition> ``` 設定一個進場由透明度 0 變 1 並由右測 `100px` 處滑入,並且進場、離場分別設定不同的曲線函數: ```css .fade-enter, .fade-leave-to { opacity: 0; transform: translateX(100px); } .fade-leave, .fade-enter-to { opacity: 1; } .fade-enter-active { transition: all 0.3s ease; } .fade-leave-active { transition: all 0.8s cubic-bezier(1, 0.5, 0.8, 1); } ``` <iframe height="265" style="width: 100%;" scrolling="no" title="Vue CSS 轉場 轉場範例" src="https://codepen.io/CHUPAIWANG/embed/MWYeZvd?height=265&theme-id=default&default-tab=result" frameborder="no" allowtransparency="true" allowfullscreen="true"> See the Pen <a href='https://codepen.io/CHUPAIWANG/pen/MWYeZvd'>Vue CSS 轉場 轉場範例</a> by CHUPAIWANG (<a href='https://codepen.io/CHUPAIWANG'>@CHUPAIWANG</a>) on <a href='https://codepen.io'>CodePen</a>. </iframe> 再舉一個例子,由下往上進場,由右出場: ```css .fade-enter { opacity: 0; transform: translateY(100%); } .fade-enter-to, .fade-leave { opacity: 1; } .fade-leave-to { opacity: 0; transform: translateX(100%); } .fade-enter-active,.fade-leave-active { transition: all 0.8s ease; } ``` <iframe height="265" style="width: 100%;" scrolling="no" title="Vue CSS 轉場 轉場範例2" src="https://codepen.io/CHUPAIWANG/embed/zYGzQXB?height=265&theme-id=dark&default-tab=result" frameborder="no" allowtransparency="true" allowfullscreen="true"> See the Pen <a href='https://codepen.io/CHUPAIWANG/pen/zYGzQXB'>Vue CSS 轉場 轉場範例2</a> by CHUPAIWANG (<a href='https://codepen.io/CHUPAIWANG'>@CHUPAIWANG</a>) on <a href='https://codepen.io'>CodePen</a>. </iframe> ### 2. CSS `animation` CSS `animation` 用法同 CSS `transition`,區別是在動畫中 `v-enter` 類名在節點插入 DOM 後不會立即刪除,而是在 `animationend` 事件觸發時刪除。 ```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.5); } 100% { transform: scale(1); } } ``` <iframe height="265" style="width: 100%;" scrolling="no" title="Vue CSS 轉場 動畫範例" src="https://codepen.io/CHUPAIWANG/embed/xxbOmjV?height=265&theme-id=default&default-tab=result" frameborder="no" allowtransparency="true" allowfullscreen="true"> See the Pen <a href='https://codepen.io/CHUPAIWANG/pen/xxbOmjV'>Vue CSS 轉場 動畫範例</a> by CHUPAIWANG (<a href='https://codepen.io/CHUPAIWANG'>@CHUPAIWANG</a>) on <a href='https://codepen.io'>CodePen</a>. </iframe> ## 使用自訂義類別名稱 我們可以通過以下 `transition` 元件特性來使用自訂義類別名稱: - `enter-class` - `enter-active-class` - `enter-to-class` **2.1.8+** - `leave-class` - `leave-active-class` - `leave-to-class` **2.1.8+** 他們的優先級高於普通的類別名稱。 舉個簡單得範例,來說明使用方式: ```css .opacity-0 { opacity: 0; } .trs-time-3 { transition-duration: 3s; } ``` ```htmlmixed <transition enter-class="opacity-0" leave-to-class="opacity-0" enter-active-class="trs-time-3" leave-active-class="trs-time-3" > <div class="box" v-if="show"></div> </transition> ``` <iframe height="265" style="width: 100%;" scrolling="no" title="Vue CSS 轉場 自訂義 class" src="https://codepen.io/CHUPAIWANG/embed/JjoRGpG?height=265&theme-id=default&default-tab=result" frameborder="no" allowtransparency="true" allowfullscreen="true"> See the Pen <a href='https://codepen.io/CHUPAIWANG/pen/JjoRGpG'>Vue CSS 轉場 自訂義 class</a> by CHUPAIWANG (<a href='https://codepen.io/CHUPAIWANG'>@CHUPAIWANG</a>) on <a href='https://codepen.io'>CodePen</a>. </iframe> ### 1. 第三方 CSS 動畫庫 自訂義類別名稱,對於套用第三方 CSS 動畫庫結合非常方便。 舉例來說,使用 [Animate.css](https://daneden.github.io/animate.css/) 的動畫效果: ```htmlmixed <button v-on:click="show = !show"> Toggle </button> <transition enter-active-class="animated tada" leave-active-class="animated bounceOutRight" > <div class="box" v-if="show"></div> </transition> <transition enter-active-class="animated fadeInUp" leave-active-class="animated flipInY" > <div class="box" v-if="show"></div> </transition> ``` <iframe height="500" style="width: 100%;" scrolling="no" title="Vue CSS 轉場 Animate.css" src="https://codepen.io/CHUPAIWANG/embed/dyPpYJB?height=265&theme-id=default&default-tab=result" frameborder="no" allowtransparency="true" allowfullscreen="true"> See the Pen <a href='https://codepen.io/CHUPAIWANG/pen/dyPpYJB'>Vue CSS 轉場 Animate.css</a> by CHUPAIWANG (<a href='https://codepen.io/CHUPAIWANG'>@CHUPAIWANG</a>) on <a href='https://codepen.io'>CodePen</a>. </iframe> 或者是 [magic.css](https://www.minimamente.com/project/magic/): ```htmlmixed <button v-on:click="show = !show"> Toggle </button> <transition enter-active-class="magictime foolishIn" leave-active-class="magictime tinDownOut" > <div class="box" v-if="show"></div> </transition> ``` <iframe height="500" style="width: 100%;" scrolling="no" title="Vue CSS 轉場 magic" src="https://codepen.io/CHUPAIWANG/embed/NWPRGYj?height=265&theme-id=default&default-tab=result" frameborder="no" allowtransparency="true" allowfullscreen="true"> See the Pen <a href='https://codepen.io/CHUPAIWANG/pen/NWPRGYj'>Vue CSS 轉場 magic</a> by CHUPAIWANG (<a href='https://codepen.io/CHUPAIWANG'>@CHUPAIWANG</a>) on <a href='https://codepen.io'>CodePen</a>. </iframe> ## 轉場時間 ### 1. 同時使用 `transition/animation` Vue 為了知道轉場的完成,必須設置相應的事件監聽器。它可以是 `transitionend` 或 `animationend`,這取決於給元素應用的 CSS 規則。如果你使用其中任何一種,Vue 能自動識別類型並設置監聽。 但有時候會遇到需要同時設置的情況,但兩邊的完成時間不一致,這時候就需要手動設置 `transitionend` 或 `animationend` 來明確告知 Vue 要監聽的類型。 舉例來說,假設你分別使用自訂義的類別名稱和 Animate.css : ```css .fade-enter,.fade-leave-to { opacity: 0; } .fade-enter-to, .fade-leave { opacity: 1; } .fade-enter-active,.fade-leave-active { transition: opacity 3s; } ``` ```htmlmixed <transition name="fade" type="transition" enter-active-class="animated swing fade-enter-active" leave-active-class="animated bounce fade-leave-active" > <div class="box" v-if="show"></div> </transition> ``` 這裡要注意,使用自訂義類別名稱優先度大於普通的類別名稱,所以`fade-enter-active` 和 `fade-leave-active` 記得要補上。 Animate.css 預設動畫時間為 1s,而我們設置的 `transition` 時間為 3s,Animate.css 的動畫很外就觸發完成了,而轉場還沒結束。在很多情況下,Vue 可以自動得出轉場效果的完成時機,但還是有可能出現例外。 為了避免出現例外,你就需要手動設定 `type="transition"` 以 `transition` 的時間為準。反之動畫時間大於轉場就以動畫時間為準。 <iframe height="265" style="width: 100%;" scrolling="no" title="Vue CSS 轉場 同时使用轉場和動畫" src="https://codepen.io/CHUPAIWANG/embed/BayLoXZ?height=265&theme-id=default&default-tab=result" frameborder="no" allowtransparency="true" allowfullscreen="true"> See the Pen <a href='https://codepen.io/CHUPAIWANG/pen/BayLoXZ'>Vue CSS 轉場 同时使用轉場和動畫</a> by CHUPAIWANG (<a href='https://codepen.io/CHUPAIWANG'>@CHUPAIWANG</a>) on <a href='https://codepen.io'>CodePen</a>. </iframe> ### 2. 顯性的轉場持續時間 上面已經提過了,在很多情況下,Vue 可以自動得出轉場效果的完成時機。預設情況下,Vue 會等待其在轉場效果的根元素的第一個 `transitionend` 或 `animationend` 事件。 但在某些情況下,還可以自定義整個動態效果總時間長,使用的是 `duration` 特性搭配 `v-bind`。 舉例來說,總時常為 5s: ```htmlmixed <transition :duration="5000">...</transition> ``` 也可以分別設定進入和移除持續時間: ```htmlmixed <transition :duration="{ enter: 500, leave: 800 }">...</transition> ``` 這是一個 `transition` 需要 5秒,但總轉場時間強制設為 1秒的範例: <iframe height="265" style="width: 100%;" scrolling="no" title="Vue CSS 轉場 顯性的轉場持續時間" src="https://codepen.io/CHUPAIWANG/embed/mdJwNwe?height=265&theme-id=dark&default-tab=result" frameborder="no" allowtransparency="true" allowfullscreen="true"> See the Pen <a href='https://codepen.io/CHUPAIWANG/pen/mdJwNwe'>Vue CSS 轉場 顯性的轉場持續時間</a> by CHUPAIWANG (<a href='https://codepen.io/CHUPAIWANG'>@CHUPAIWANG</a>) on <a href='https://codepen.io'>CodePen</a>. </iframe> ## 初始渲染的轉場 透過設定 `appear` 特性,設置節點在初始渲染的轉場。 ```htmlmixed <transition appear> <!-- ... --> </transition> ``` >[CodePen](https://codepen.io/CHUPAIWANG/full/dyPpJKO),載入畫面時,會有進場效果。 `appear` 預設使用進場的類別,如果要與進場套用不同的動畫效果,需要使用自定義的類別名稱: ```htmlmixed <transition appear appear-class="custom-appear-class" appear-to-class="custom-appear-to-class" (2.1.8+) appear-active-class="custom-appear-active-class" > <!-- ... --> </transition> ```