基礎からメモ: Vue.js CH6-p198 単一要素トランジション

<transition>タグの中に1つだけ存在する要素に対し使用するものを「単一要素トランジション」と呼ぶ。

単一要素トランジションで使用するトランジションクラス

Enter系Leave系の2つのフェーズがあり、それぞれ3種、計6種のクラスがある。 Enter系は対象要素がDOMに追加されたときのフェーズ(表示時)、Leave系は逆に対象要素がDOMから削除された時のフェーズ(非表示時)。

基本は追加時と削除時の次の2つの組合せ

  • 追加時: .v-enter => .v-enter-to
  • 削除時: .v-leave => .v-leave-to

他に.v-enter-active.v-leave-activeクラスがあり、それぞれEnter時とLeave時のアクティヴ状態を表す。

/* トランジション中に有効 */
.v-enter-active, .v-leave-active {
  transition: opacity 1s;
}

/* 表示される時 */
.v-enter {
  opacity: 1;
}
.v-enter-to {
  opacity: 1;
}

/* 消える時 */
.v-leave {
  opacity: 1;
}
.v-leave-to {
  opacity: 0;
}

指定が何も無い場合はもともとopacity: 1なので、.v-enter-to.v-leaveは省略でき、同じスタイルはまとめて次のように書ける。

/* 1秒かけて透明度を遷移 */
.v-enter-active, .v-leave-active {
  transition: opacity 1s;
}
/* 見えなくなるときの透明度 */
.v-enter, .v-leave-to {
  opacity: 0;
}

Enter と Leave でスタイルを別にする

表示は左からフワッと現れ、消える時はフワッと下へ消える

/* 1秒かけて透明度を遷移 */
.v-enter-active, .v-leave-active {
  transition: opacity 1s, transform 1s;
}
/* 表示は左から */
.v-enter {
  opacity: 0;
  transform: translateX(-20px);
}

/* 消える時は下へ */
.v-leave-to {
  opacity: 0;
  transform: translateY(20px);
}

複数の要素をグループ化

<transition>タグの中に要素が複数あっても、描画結果が一つなら単一トランジションとして扱える。

<transition>
  <div v-if="show" key="a">TRUE</div>
  <div v-else key="b">FALSE</div>
</transition>

この例の場合、TRUEとFALSEの切り替わり時に、表示がカクッとなっておかしいが、position:absoluteを片方のクラスに指定することで自然になる。

.v-leave-active {
  position: absolute;
}

Enter と Leave のタイミングを変更する

トランジションは通常では Enter と Leave の処理を同時に行うが、mode属性を付与することでタイミングを変更できる。

  • in-out: Enterが終わってからLeaveを開始
  • out-in: Leaveが終わってからEnterを開始
<transition mode="out-in">
  <div v-if="show" key="a">TRUE</div>
  <div v-else key="b">FALSE</div>
</transition>

この例だとTRUE又はFALSEの表示が完全に消えてからもう一つの表示が始まる。(つまり2つの表示は全く重ならない) これをin-outにすると完全に次の表示がなされてから前のが消え始める(つまり一時的に2つの表示は重なる)。

特定のデータの変化でトランジションを発動させる

特定のデータの変化をトリガーとして、トランジションを発動させることもできる。

countプロパティを要素のキーに設定し、ボタンを押してcountの数値が変わるとそれをゆっくり表示する。

<div id="app">
  <p><button v-on:click="count++">切り替え</button></p>
  <transition>
    <div v-bind:key="count">{{ count }}</div>
  </transition>
</div>
var app = new Vue({
  el: '#app',
  data: {
    count: 0
  }
});
.v-enter-active, .v-leave-active {
  transition: opacity 1s;
}
.v-leave-active {
  position: absolute;
}

.v-enter, .v-leave-to {
  opacity: 0;
}

同じことをコンポーネントでやってみた例

<transition>
  <my-label v-bind:count="count" v-bind:key="count"></my-label>
</transition>
Vue.component('my-label', {
  template: '<p>{{ count }}</p>',
  props: ["count"]
});

var app = new Vue({
  el: '#app',
  data: {
    count: 0
  }
});