# transition-group 元件
>[竹白記事本](https://chupainotebook.bloggi.co/)
[Vue Transition|目錄](https://hackmd.io/@chupai/HkQQA8c4U)
###### tags: `Vue Transition` `竹白的 Vue.js 學習筆記`
## 大量元素的轉場
目前為止,都是針對單個節點,或是同一時間渲染多個節點中的一個。如果要針對由 `v-for` 產生的大量元素(例如:列表),就要改為使用 transition-group 元件。
transition-group 元件有以下幾個特點:
- 不同於 `<transition>`,它會以一個真實元素呈現:預設為一個 `<span>`。可以通過 `tag` 特性更換為其他元素。
- 轉場模式(`in-out` 與 `out-in`)不可用,因為我們不再相互切換特有的元素。
- 內部元素 **總是需要** 提供唯一的 `key` 屬性值。
- CSS 轉場的類將會應用在內部的元素中,而不是這個組/容器本身。
### 1. 進入/離開的轉場
首先我們看一段程式碼:
```htmlmixed
<button v-on:click="add">Add</button>
<button v-on:click="remove">Remove</button>
<ul>
<li v-for="item in items" :key="item" class="list-item">
{{ item }}
</ul>
```
按下 Add 會隨機插入數字,按下 Remove 會隨機移除數字。
<iframe height="265" style="width: 100%;" scrolling="no" title="Vue 大量元素的轉場 " src="https://codepen.io/CHUPAIWANG/embed/povELjR?height=265&theme-id=dark&default-tab=result" frameborder="no" allowtransparency="true" allowfullscreen="true">
See the Pen <a href='https://codepen.io/CHUPAIWANG/pen/povELjR'>Vue 大量元素的轉場 </a> by CHUPAIWANG
(<a href='https://codepen.io/CHUPAIWANG'>@CHUPAIWANG</a>) on <a href='https://codepen.io'>CodePen</a>.
</iframe>
接下來我們改用 transition-group 元件,增加轉場效果。
transition-group 元件預設會有一個 `<span>` 的根元素,它會包住由 `v-for` 產生的多個元素當成其子元素。
我們透過 `tag` 特性,將其改成 `<ul>`:
```htmlmixed
<transition-group name="list" tag="ul">
<li v-for="item in items" v-bind:key="item" class="list-item">
{{ item }}
</li>
</transition-group>
```
並加上 CSS:
```css
.list-enter,
.list-leave-to {
opacity: 0;
transform: translateY(100%);
}
.list-leave,
.list-enter-to {
opacity: 1;
}
.list-enter-active,
.list-leave-active {
transition: all 1s;
}
```
<iframe height="265" style="width: 100%;" scrolling="no" title="Vue 大量元素的轉場 - transition-group" src="https://codepen.io/CHUPAIWANG/embed/RwPZgwM?height=265&theme-id=dark&default-tab=result" frameborder="no" allowtransparency="true" allowfullscreen="true">
See the Pen <a href='https://codepen.io/CHUPAIWANG/pen/RwPZgwM'>Vue 大量元素的轉場 - transition-group</a> by CHUPAIWANG
(<a href='https://codepen.io/CHUPAIWANG'>@CHUPAIWANG</a>) on <a href='https://codepen.io'>CodePen</a>.
</iframe>
不過這個範例有一個明顯問題,當新增和移除元素的時候,周圍的元素會瞬間移動到他們的新佈局的位置,這會顯得不自然,我們將會在之後解決這個問題。
### 2. 排序轉場
transition-group 元件還有一個特殊之處。不僅可以進入和離開動畫,還可以改變定位。
`v-move` 特性,它會在元素的改變定位的過程中應用。像之前的列別名稱一樣,可以通過 `name` 屬性來自定義前綴,也可以通過 `move-class` 屬性手動設置。
`v-move` 對於設置轉場的切換時機和轉場曲線非常有用。
```htmlmixed
<button v-on:click="items.reverse()">Reverses</button>
<transition-group name="flip-list" tag="ul">
<li
v-for="item in items"
:key="item"
class="list-item">{{ item }}
</li>
</transition-group>
```
```css
.flip-list-move {
transition: transform 1s;
}
```
```javascript
const vm = new Vue({
el: '#app',
data: {
items: [1, 2, 3, 4, 5, 6, 7, 8, 9],
},
});
```
<iframe height="400" style="width: 100%;" scrolling="no" title="Vue 大量元素的轉場 - v-move" src="https://codepen.io/CHUPAIWANG/embed/bGNwzwz?height=265&theme-id=default&default-tab=result" frameborder="no" allowtransparency="true" allowfullscreen="true">
See the Pen <a href='https://codepen.io/CHUPAIWANG/pen/bGNwzwz'>Vue 大量元素的轉場 - v-move</a> by CHUPAIWANG
(<a href='https://codepen.io/CHUPAIWANG'>@CHUPAIWANG</a>) on <a href='https://codepen.io'>CodePen</a>.
</iframe>
Vue 使用了一個叫 [FLIP](https://aerotwist.com/blog/flip-your-animations/) 簡單的動畫隊列。使用 `transforms` 將元素從之前的位置平滑轉場新的位置。
讓我們修正上節不自然的的程式碼:
```css
.list-move-active {
position: absolute;
}
.list-move {
transition: 1s;
}
```
<iframe height="265" style="width: 100%;" scrolling="no" title="Vue 大量元素的轉場 - 進入/離開的轉場 v-move" src="https://codepen.io/CHUPAIWANG/embed/KKwgJNO?height=265&theme-id=default&default-tab=result" frameborder="no" allowtransparency="true" allowfullscreen="true">
See the Pen <a href='https://codepen.io/CHUPAIWANG/pen/KKwgJNO'>Vue 大量元素的轉場 - 進入/離開的轉場 v-move</a> by CHUPAIWANG
(<a href='https://codepen.io/CHUPAIWANG'>@CHUPAIWANG</a>) on <a href='https://codepen.io'>CodePen</a>.
</iframe>
:::danger
另外要注意,FLIP 轉場的元素不能設置為 `display: inline`。作為替代方案,可以設置為 `display: inline-block`、`display: flex-block` 或者放置於 FlexBox 父容器中
:::
<iframe height="500" style="width: 100%;" scrolling="no" title="Vue 大量元素的轉場 - 打亂" src="https://codepen.io/CHUPAIWANG/embed/VwLzMxp?height=265&theme-id=dark&default-tab=result" frameborder="no" allowtransparency="true" allowfullscreen="true">
See the Pen <a href='https://codepen.io/CHUPAIWANG/pen/VwLzMxp'>Vue 大量元素的轉場 - 打亂</a> by CHUPAIWANG
(<a href='https://codepen.io/CHUPAIWANG'>@CHUPAIWANG</a>) on <a href='https://codepen.io'>CodePen</a>.
</iframe>