Vue.js の transition-group で
リストのアニメーションに挑戦
以前、Jazz の歴史本を題材に Vue.js と YouTube API をつかったプレイリストページを作りました。
ページでは、曲の表示/並べ替え/フィルター/文字列検索の機能があり、いずれも Vue.js が大活躍してくれました。公開してから2ヶ月経ち、当初はわからなかったアニメーションのさせかたを知ったので追加しました。そして備忘録としてブログを書きたいと思います。
以下のリンクを参考にしたので合わせてどうぞ。公式ドキュメントの充実具合がさすがですね。
- Enter/Leave とトランジション一覧 — Vue.js
- Vue.js でたのしいトランジション 通常編 | Cubix
- Vue.js でたのしいトランジション リスト編 | Cubix
- Vue.js で「東京大学のアルバート・アイラー」を並べ替える – nujawak.online
Vue.js でリストをアニメーションさせるには
Vue.js でリストをアニメーションさせるにはtransition-group
を使ってあげます。Vue の専門用語としては「トランジション」なようですが、どうもピンとこないので私は「アニメーション」と呼びたいと思います。
さて、このアニメーションですが、複数の実装方法が提供されているようです。今回は1番の、CSSクラスを使ったシンプルな方法を用います。
- 自動適用される CSS クラスを使う
- サードパーティの CSS アニメーションライブラリと組み合わせる
- JavaScript フックを使う
- サードパーティの JavaScript アニメーションライブラリと組み合わせる
さらに以下のことも可能です。文言は公式ドキュメントのママ。
本当の限界はあなたの想像力だけなのです。
とさえ書いてありますね。格好良い!
ビフォー/アフターでみる transition-group コンポーネント
アニメーションを使わず即時に変化される場合と、アニメーションを使ってイイ感じに変化する場合の HTML を見比べてみます。
<div class="list"> <div class="item" v-for="item in items"> {{item.title}} </div> </div>
<transition-group tag="div" class="list" name="vue-anime-list"> <div class="item" v-for="item in items" :key="item"> {{item.title}} </div> </transition-group>
単純なリストレンダリングにはv-for
を使ってあげれば OK でした。これをアニメーションさせるには、v-for
を囲うようにtransition-group
を使います。
transition-group
にはtag
属性をつけて、最終的なHTMLタグを指定する。省略するとspan
。transition-group
にはname
属性をつけて、CSS クラスの接頭語を指定する。省略するとv-
。v-for
の要素には、ユニークな、一意なkey
属性をつける。これは必須。
これで以下の CSS クラスが使えるようになります。
.vue-anime-list-enter
.vue-anime-list-enter-to
.vue-anime-list-enter-active
.vue-anime-list-leave
.vue-anime-list-leave-to
.vue-anime-list-leave-active
.vue-anime-list-move
name
を省略した場合はv-enter
などになります。ただしto
に関してはバージョン 2.1.8 以降でのみ利用可能なようです。
enter, leave, move
任意に設定した接頭語に対して、enter
, leave
, move
, to
, active
を組み合わせたクラスが追加されることがわかります。まずは、enter
, leave
, move
の違いをみていきましょう。
enter
はデータが挿入される前に追加されます。例えば、ページにアクセスした一番最初に vue が描画する時、検索条件が緩くなり合致するアイテムが増えた時などが当てはまります。leave
はデータが削除される前で、検索によって絞り込まれて除外されるアイテムなどに適用されます。move
は、並べ替えなどで位置が変化するときが当てはまります。
ゼヒ実際に試してみてほしいのですがmove
すごくないですか?公式ドキュメントでも魔法のように見えるかもしれませんが
と書いていますね。なんでも FLIP というアニメーションテクニックを使っているようです。
無印, to, active
つづけて、to
, active
。これは本家の図を拝借しちゃいましょう。

無印がアニメーションの開始時点を現し、to
がアニメーションの終了時点を現します。それらを通してずっとactive
が付くといった考えです。これはenter
もleave
も共通です。
私は、リンクのa
タグと:hover
で CSS アニメーションをつける場合と比べて理解しました。
a, .vue-anime-enter-active{ background: #000; border: 1px solid #000; border-radius: 3px; transition: background 0.5s ease 0s; } a:hover, .vue-anime-enter-to{ background: #fff; }
こんなスタイルを書きますよね。ボタンをホバーするとフワっと背景色が変わる、みたいな。これと同じで CSS クラスに合わせてスタイルを当てていけばアニメーションが作れます。@keyframes
を使う場合も基本的には同様。便利。すごい。さすが Vue.js。
CSS アニメーションライブラリを利用したい場合はカスタムクラスを用いると便利で、enter-active-class
などの属性を使うことができます。
<transition-group tag="div" class="list" name="vue-anime-list" enter-active-class="animated tada"> <div class="item" v-for="item in items" :key="item"> {{item.title}} </div> </transition-group>
東京大学のアルバート・アイラー YouTube まとめでの実例
ここまでできれば、かなりのアニメーションが作れると思います。オンとオフのクラスさえ把握してしまえば、あとは CSS のことだけを考えれば良いわけですから。
最後に今回私が作ったスタイルを掲載して締めたいと思います。SCSS を使って Vue の接頭語をまとめてしまうと楽ですね。実際の動きは、冒頭の動画やページで確認してみてくださいね。
.vue-anime-list{ &-enter-active{ opacity: 0; transform: translateX(50px); transition: { property : transform, opacity; duration : 0.6s; timing-function: cubic-bezier(0.77, 0, 0.175, 1); delay: : 0s; } } &-enter-to{ opacity: 1; transform: translateX(0); } &-leave-active{ opacity: 1; transform: translateX(0); transition: { property : transform, opacity; duration : 0.6s; timing-function: cubic-bezier(0.77, 0, 0.175, 1); delay: : 0s; } } &-leave-to{ opacity: 0; transform: translateX(50px); } &-move{ transition: { property : transform; duration : 0.6s; timing-function: cubic-bezier(0.77, 0, 0.175, 1); delay : 0s; } } }
それではよいお年を。