Vue.jsには、HTMLのテンプレート要素に対してアニメーションの効果を与える仕組みが標準で用意されています。
アニメーションの機能を利用する事で、要素を追加したり、削除したりするタイミングで、要素をスライドさせたり、フェードインやフェードアウトの効果を与えることができます。
今回は、Vue.jsでアニメーション効果を実装するために用意されている組込コンポーネントの<transition>要素について紹介します。
transition: トランジションとは「移行」「推移」「変換」などの意味を持つ言葉で、物事がある段階(状態)から次の段階(状態)に移行することを指します。
前の段階と後のダイン会を繋ぐために挟まれる効果(エフェクト)が、トランジションです。
目次
<transition>要素
アニメーション機能を与えるために使用する<transition>要素は、アニメーションを行う要素は囲むように配置(記述)します。
1 2 3 |
<transition> <div v-show="isShow">トランジション</div> </transition> |
アニメーション機能
Vue.jsのアニメーションは、次の機能との連携を行うことができます。
- 条件付きの表示 (v-show)
- 条件付きの描画 (v-if)
- リストへの追加、削除 (v-for)
- 動的コンポーネント
- コンポーネントルート要素
Vue.jsのアニメーションはディレクティブや属性の変化を検知して、自動でクラス(CSS)を付与します。
付与されるクラス
<transition>要素で自動で付与されるクラスは、次のようになります。
クラス名 | 付与されるタイミングと説明 |
---|---|
v-enter-from | 要素が表示される前、または出現する前に付与されます。 アニメーションの開始時に削除されるクラスになります。 表示・出現のアニメーションの初期スタイルを適用するために使用します。 |
v-enter-to | 要素の表示または出現のアニメーションの開始時に付与されます。 アニメーション終了後に削除されるクラスになります。 アニメーションの最終的なスタイルを適用するために使用します。 |
v-enter-active | 要素が表示される前、または出現する前からアニメーションの終了前まで付与されます。 Transitionのスタイルを適用するために使用します。 |
v-leave-from | 要素が非表示になる前、または消滅する前に付与されます。 アニメーションの開始時に削除されるクラスになります。 非表示・消滅のアニメーションの初期スタイルを適用するために使用します。 |
v-leave-to | 要素の非表示または消滅のアニメーションの開始時に付与されます。 アニメーション終了後に削除されるクラスになります。 アニメーションの最終的なスタイルを適用するために使用します。 |
v-leave-active | 要素が非表示になる前、または消滅する前からアニメーションの終了前まで付与されます。 Transitionのスタイルを適用するために使用します。 |
<transition>要素で自動で付与されるクラスの名前は、すべて「v-」という接頭語が付いています。(「v-enter~」「v-leave~」)
これらの名前の接頭語は変更することが可能です。
接頭語を変更する場合は、<transition>要素のname属性を指定します。
例えば <transition name=”anime”> とすると、「v-enter-from」は「anime-enter-from」、「v-leafe-to」は「anime-leave-to」などのクラス名に変化します。
アニメーションの設定例
ここでは、CSSのスタイル(クラス)を定義して、アニメーションを設定する例を示します。
1 2 3 4 5 6 |
<div id="app"> <transition> <div v-show="isShow">transition サンプル</div> </transition> <button v-on:click="isShow = !isShow">表示・非表示 トグル</button> </div> |
1 2 3 4 5 6 7 |
Vue.createApp({ data: function() { return { isShow: false } } }).mount('#app') |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
.v-enter-from, .v-leave-to { opacity: 0; } .v-enter-active, .v-leave-active { transition: opacity 300ms ease; } .v-enter-to, .v-leave-from { opacity: 1; } |
上記の例では、transition要素に囲まれたdiv要素をv-showディレクティブを使用して表示または非表示にしています。要素の表示と非表示はbutton要素(表示・非表示 トグルボタン)をクリックすることで切り替えることができます。
v-showディレクティブにバインドするデータは、VueインスタンスのdataオプションにisShowというプロパティで定義しています。
isShowの真偽値(true / false)によって要素の表示と非表示が設定されます。
v-showディレクティブを指定した要素のラッパーとなるtransition(コンポーネント)が表示と非表示の設定値を検知し、トランジションに必要なクラス名を付与するようになります。
CSS(スタイルシート)では、要素の表示と非表示の開始時の状態やトランジションのスタイルを定義しています。(
ここではenterとleaveとも同じスタイルを定義していますが、enterとleaveで別々のスタイルを定義することも可能です。)
上記のサンプルコードをブラウザーで実行すると、表示・非表示 トグルボタンをクリックごとにv-showディレクティブを指定したdiv要素がフェードインして表示され、フェードアウトして非表示になります。
アニメーションの設定例としていくつかサンプルを掲載しておきます。
CSS トランジション
1 2 3 4 5 6 7 8 9 |
<div id="app"> <button @click="isShow= !isShow"> 描画(トグル) </button> <transition name="slide-fade"> <p v-if="isShow">transitionサンプル</p> </transition> </div> |
1 2 3 4 5 6 7 8 9 |
const app = { data() { return { isShow: true } } } Vue.createApp(app).mount('#app') |
1 2 3 4 5 6 7 8 9 10 11 12 13 |
.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; } |
CSS アニメーション
1 2 3 4 5 6 7 8 |
<div id="app"> <button @click="isShow = !isShow">Toggle show</button> <transition name="bounce"> <p v-if="isShow"> Vue.jsのトランジションを使用すると簡単にアニメーションを実装することができます。 </p> </transition> </div> |
1 2 3 4 5 6 7 8 9 |
const app = { data() { return { isShow: true } } } Vue.createApp(app).mount('#app') |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
.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-group>要素
v-forディレクティブで複数の要素を描画する処理に対してトランジションを使ったアニメーションを行いたい場合は、組込コンポーネントの<transition-group>要素を使用します。
<transition-group>要素は、HTML出力時にデフォルトでは要素が描画されません。<transition-group>要素で要素を出力したい場合は、tag属性に要素名を指定します。
1 |
<transition-group tag="要素名"> |
CSSのクラス名は<transition-group>要素で囲まれた要素(<transition-group>要素が内包する要素)に対して付与されます。
<transition-group>要素の中に配置する要素にはkey属性が必要になります。
以下に<transition-group>要素を使用した実装例を示します。
1 2 3 4 5 6 7 8 9 |
<div id="app"> <button v-on:click="itemState = !itemState">フィルター トグル</button> <transition-group tag="ul"> <li v-for="item in filterItems" v-bind:key="item.name"> {{item.name}} </li> </transition-group> </div> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
Vue.createApp({ data: function() { return { items: [ { name: 'アイテム 1', state: false }, { name: 'アイテム 2', state: true }, { name: 'アイテム 3', state: false }, { name: 'アイテム 4', state: true } ], itemState: false } }, computed: { filterItems: function() { if (this.itemState) { return this.items.filter(function(item) { return item.state; }); } else { return this.items; } } } }).mount('#app') |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
.v-enter-from, .v-leave-to { opacity: 0; } .v-enter-active, .v-leave-active { transition: opacity 300ms ease; } .v-enter-to, .v-leave-from { opacity: 1; } |
<transition>要素のtag属性にul要素を指定して、Vueインスタンスのdataプロパティオプションに定義したitemsプロパティの配列をリストとして描画しています。
ボタン(button要素)をクリックするとdataプロパティオプションに定義したitemStateプロパティの値(true / false)が切り替わります。
computedプロパティオプションでは、リストとして描画する項目(リストアイテム)を返しています。
itemStateがtrueの場合はitemsのデータが持つstateプロパティの値がtrueのデータのみ返しています。itemStateがfalseの場合はitemsをそのまま返しています。
JavaScript フック
<transition>要素ではCSSでトランジションのスタイルを定義する以外にも、JavaScriptでトランジションの制御をすることができます。
JavaScriptフックは、アニメーションライブラリなどと組み合わせて利用することができます。
JavaScriptで制御する場合は、トランジション中に実行されるイベントをタイミングごとに指定します。
JavaScriptフックとして用意されているイベントには以下のものがあります。
イベント名 | 呼び出されるタイミング |
---|---|
before-enter | 要素が表示または出現する前に呼び出されます。 |
enter | 要素が表示または出現してアニメーションが実行される前に呼び出されます。 |
after-enter | 要素が表示または出現してアニメーションが実行された後に呼び出されます。 |
enter-cancelled | 要素の表示または出現がキャンセルされる時に呼び出されます。 |
before-leave | 要素が非表示または消滅する前に呼び出されます。 |
leave | 要素が非表示または消滅してアニメーションが実行される前に呼び出されます。 |
after-leave | 要素が非表示または消滅してアニメーションが実行された後に呼び出されます。 |
leave-cancelled | 要素の非表示または消滅がキャンセルされる時に呼び出されます。 |
JavaScriptフックは、イベントなので<transition>要素のv-onディレクティブでバインドします。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
<div id="app"> <transition v-on:before-enter="beforeEnter" v-on:enter="enter" v-on:after-enter="afterEnter" v-on:enter-cancelled="enterCancelled" v-on:before-leave="beforeLeave" v-on:leave="leave" v-on:after-leave="afterLeave" v-on:leave-cancelled="leaveCancelled" v-bind:css="false" > <div v-show="isShow"> トランジション </div> </transition> </div> |
バインドする処理(イベントメソッド)は、Vueインスタンスのmethodsプロパティオプションに定義するメソッド(関数)になります。
トランジションのアニメーションをJavaScriptのみで制御する場合は、css属性にfalseを指定します。(v-bindディレクティブを使用してcss属性にfalseを指定します。)
css属性にfalseを指定することで、わずかにパフォーマンスが改善するほか、CSSのルールの誤ったトランジションへの干渉を防ぐことができます。
各イベントリスナーのメソッド(関数)には、第1引数(パラメーター)にトランジションする要素が渡されます。
引数で受け取った要素のstyleプロパティンなどを操作することで、各タイミングでの要素の状態を定義します。
enterイベントとleaveイベントでは、第2引数にアニメーションの完了をVueインスタンスに知らせるためのコールバック関数が渡されます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
Vue.createApp({ data: function() { return { isShow: false } }, methods { beforeEnter: function(el) { // ここで要素が表示または出現する前の状態を定義します。 }, enter: function(el, done) { // ここで要素が表示または出現するアニメーションを実行します。 // アニメーションが完了したらdoneコールバック関数を呼び出します。 }, afterEnter: function(el) { // ここで要素が表示または出現した後の状態を定義します。 }, enterCancelled: function(el) { // ここで要素の表示または出現がキャンセルされた時の状態を定義します。 }, beforeLeave: function(el) { // ここで要素が非表示または消滅する前の状態を定義します。 }, leave: function(el, done) { // ここで要素が非表示または消滅するアニメーションを実行します。 // アニメーションが完了したらdoneコールバック関数を呼び出します。 }, afterLeave: function(el) { // ここで要素が非表示または消滅した後の状態を定義します。 }, leaveCancelled: function(el) { // ここで要素の非表示または消滅がキャンセルされた時の状態を定義します。 } } }).mount('#app') |
トランジションにJavaScriptのみを利用する場合や、アニメーションライブラリなどを使用している場合は、アニメーションの完了時にdoneコールバック関数をenterイベントとleaveイベントフックで呼び出します。呼ばない場合は、フックは同期的に呼ばれ、トランジションは直ちに終了します。
アニメーション機能使用時の注意点
<transition>要素を利用したアニメーション効果の適用は、アプリケーションを利用するユーザーに注目してほしいコンテンツを効果的に見せたい場合にとても効果的です。
しかし、なんでもかんでもアニメーション効果を与えればいいというものではありません。アニメーション効果が多すぎるとユーザーによっては不快に感じる方もいます。また、アプリケーションのパフォーマンスに影響を与える場合もあります。
アニメーション機能を実装する場合は濫用は避け、必要な個所にのみ適用するようにしてください。