トランジション

Vue.js のトランジション (Transition) システムを使用すると、DOM から要素を取得したり削除するといったトランジションエフェクトを自動的に適用できます。Vue.js は自動的に、適切な時に、あなたのために CSS トランジションまたはアニメーションをトリガするため、CSS クラスを追加または削除し、そしてトランジションの間は、カスタム DOM の操作をするために、JavaScript フック関数を提供することができます。

トランジションエフェクトを適用するために、対象要素で特別な transition 属性を使用する必要があります:

<div v-if="show" transition="my-transition"></div>

transition 属性は以下と一緒に使用することができます:

トランジションを持つ要素が挿入または削除されるとき、Vue は以下となります:

v-transition="my-transition" というディレクティブを適用した場合:

  1. "my-transition" の ID を使用して、Vue.transition(id, hooks) または、transitions オプションを通じて登録された JavaScript のトランジションのフックオブジェクトを探します。それが見つかると、さまざまな段階で、適切なフックを呼びます。

  2. 自動的に、対象の要素に CSS トランジションか CSS アニメーションが適用されているか調べ、適切なタイミングで CSS クラスを追加/削除します。

  3. JavaScript フックが何も提供されず、CSS トランジション/アニメーションが何も検出されない場合、DOM オペレーション (挿入/削除) は次のフレームで直ちに実行されます。

CSS トランジション

基本的な CSS トランジションは、次のようになります。

<div v-if="show" transition="expand">hello</div>

また .expand-transitionクラス、.expand-enter クラスそして .expand-leave クラスの CSS ルールを定義する必要があります。

/* 常に表示 */
.expand-transition {
transition: all .3s ease;
height: 30px;
padding: 10px;
background-color: #eee;
overflow: hidden;
}

/* .expand-enter は entering に対する開始状態を定義 */
/* .expand-leave は leaving に対する終了状態を定義 */
.expand-enter, .expand-leave {
height: 0;
padding: 0 10px;
opacity: 0;
}

動的なバインディングを使用することによって、同じ要素で異なるトランジションを実現することができます:

<div v-if="show" :transition="transitionName">hello</div>
new Vue({
el: '...',
data: {
show: false,
transitionName: 'fade'
}
})

加えて、JavaScript フックを提供できます。

Vue.transition('expand', {
beforeEnter: function (el) {
el.textContent = 'beforeEnter'
},
enter: function (el) {
el.textContent = 'enter'
},
afterEnter: function (el) {
el.textContent = 'afterEnter'
},
enterCancelled: function (el) {
// 取り消しハンドル
},

beforeLeave: function (el) {
el.textContent = 'beforeLeave'
},
leave: function (el) {
el.textContent = 'leave'
},
afterLeave: function (el) {
el.textContent = 'afterLeave'
},
leaveCancelled: function (el) {
// 取り消しハンドル
}
})
hello

トランジション CSS クラス

追加とトグルするクラス名の接頭辞は、transition 属性の値に基づきます。transition="fade" のケースでは、 3 つの CSS クラスが関与しています:

  1. .fade-transition クラスは常に与えられます。

  2. .fade-enter は、entering transition (トランジションに入っている)の開始状態を定義します。単一のフレームに適用した後に、すぐに削除されます。

  3. .fade-leave は、leaving transition (トランジションから離れている)の終了状態を定義します。leaving transition が開始するときに適用され、トランジションが終了するときに削除されます。

transition が値を持たいない場合は、クラスはデフォルトで .v-transition.v-enter そして v-leave になります。

カスタムトランジションクラス

1.0.14 で新規追加

トランジション定義でカスタムな enterClassleaveClass を指定できます。これらは従来型のクラス名を上書きします。Animate.css の例のような、既に存在する CSS アニメーションライブラリで Vue のトランジションシステムに結合したい時は役に立ちます。

<div v-show="ok" class="animated" transition="bounce">Watch me bounce</div>
Vue.transition('bounce', {
enterClass: 'bounceInLeft',
leaveClass: 'bounceOutRight'
})

トランジションタイプの宣言

1.0.14 で新規追加

Vue.js はトランジションが終了したのを知るためにイベントリスナにアタッチする必要があります。適当される CSS ルールのタイプ (type) に応じて、transitionendanimationend のどちらかできます。1 つだけまたは他のルールを適用したい場合は、Vue.js は自動的に正しいタイプを検出することができます。例えば CSS アニメーションが Vue によってトリガされ、ホバー (hover) において CSS トランジションエフェクトも持っているような、いくつかのケースで同じ要素で両方を持ちたい場合は、明示的に以下のようなタイプを宣言する必要があります。

Vue.transition('bounce', {
// Vue はこのトランジションに対して直ちに
// `animationend` イベントだけに気にかけるようになります
type: 'animation'
})

トランジションフローの詳細

show プロパティに変更があると、それに応じて Vue.js は <div> 要素を追加/削除し、以下に指定されているようにトランジションクラスを適用します。

加えて、もし enter トランジションが進行中のときに要素が削除される場合、enterCancelled フックは、変更を一掃する、または enter でタイマーが作成されるための機会を与えるために呼び出されます。逆の leaving トランジションも同じです。

上記のようなフック関数の全ては、それらの this コンテキストは関連付けられた Vue インスタンスを設定して呼び出されます。これは、コンパイルスコープの同じ規則に従います。トランジションの this コンテキストは、それがコンパイルされるているスコープを示すようになります。

最後に、enterleave は、必要に応じて、第2引数にコールバックを取ることができます。これを行うと、トランジションが終了すべきときに明示的に制御したいと示しているため、CSS の transitionendイベントを待ち受ける代わりに、Vue.js は最終的にトランジションを完了するためにコールバックを呼びだすことを期待します。例えば:

enter: function (el) {
// 第2引数はなく、トランジションと CSS トランジションイベントで決定
}

に対して

enter: function (el, done) {
// 第2引数で、`done` が呼ばれたときだけ、トランジションは終了する
}

複数要素を同時にトランジションさせる場合、Vue.js はその要素をバッチにし、自動的に連続処理を行います。

CSS アニメーション

CSS アニメーションは、CSS トランジションと同じやり方で適用することができますが、対象の要素が追加された後、animationend がコールバックされるまで v-enter クラスが削除されないという違いがあります。

例: (CSS ルールの記述は省略)

<span v-show="show" transition="bounce">Look at me!</span>
bounce-transition {
display: inline-block; /* 他の場合、スケールアニメーションは動作しません */
}
.bounce-enter {
animation: bounce-in .5s;
}
.bounce-leave {
animation: bounce-out .5s;
}
@keyframes bounce-in {
0% {
transform: scale(0);
}
50% {
transform: scale(1.5);
}
100% {
transform: scale(1);
}
}
@keyframes bounce-out {
0% {
transform: scale(1);
}
50% {
transform: scale(1.5);
}
100% {
transform: scale(0);
}
}
Look at me!

JavaScript トランジション

どんな CSS ルールの定義しなくても、JavaScript フックを利用することができます。JavaScript トランジションだけ利用するとき、done コールバックは enterleave フック向けに必須となり、そうでなければ、それらは同期的に呼ばれ、そしてトランジションはすぐに終了します。

Vue.js は CSS の検出をスキップできるため、JavaScript トランジションに対して明示的に css: false を宣言することもよいアイディアです。これは、トランジションによる偶発的な干渉からカスケードされる CSS ルールも防止します。

以下の例では、jQuery を使用してカスタムな JavaScript トランジションの定義を登録します:

Vue.transition('fade', {
css: false,
enter: function (el, done) {
// 要素は既に DOM に挿入されており、
// アニメーションが終わったとき、done は呼ばれます
$(el)
.css('opacity', 0)
.animate({ opacity: 1 }, 1000, done)
},
enterCancelled: function (el) {
$(el).stop()
},
leave: function (el, done) {
// enter と同様
$(el).animate({ opacity: 0 }, 1000, done)
},
leaveCancelled: function (el) {
$(el).stop()
}
})

次に、transition 属性によってそれ使用するとき、同じ結果になります:

<p transition="fade"></p>

スタガリングトランジション

v-fortransition を使用するとき、スタガリングトランジションを作成することが可能です。stagger、か enter-stagger、かまたは leave-stagger のいずれかの属性をトランジション要素に追加することによってこれをすることができます:

<div v-for="item in list" transition="stagger" stagger="100"></div>

または、より細かい制御のために、staggerenterStagger または leaveStagger フックを提供することができます:

Vue.transition('stagger', {
stagger: function (index) {
// 各トランジションされた項目に対して 50ms 遅延を増加させ、
// しかし最大遅延は 300ms に制限
return Math.min(300, index * 50)
}
})

例:

stagger 属性は v-if または v-show によって追加されたまたは削除されたアイテムのトランジションに影響を及ぼしません。配列への変更または v-for に提供されたオブジェクトだけが、ずらした配置へのトランジションの原因となります。