# 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>
```