Vueで複数の要素が同時に消える時のトランジション

Vueで複数の要素が同時に消える時のトランジションについて備忘録として、こちらにまとめます。

以下のようなコードがある時に、[item2]と[item3]が消えてトランジションする時の動きが意図しない動き方になる。

  <div id="app">
    <button @click="removeItems">アイテムを削除</button>
    <transition-group tag="ul" class="list">
      <li v-for="item in items" :key="item.id">
        {{ item.name }}
      </li>
    </transition-group>
  </div>

<style>
  .v-enter-active, .v-leave-active {
    transition: opacity 1s, transform 1s;
  }
  .v-leave-active {
    position: absolute;
  }
  .v-move {
    transition: transform 1s;
  }
  .v-enter, .v-leave-to {
    opacity: 0;
  }
</style>
new Vue({
  el: '#app',
  data: {
    items: [
      { id: 1, name: 'item1' },
      { id: 2, name: 'item2' },
      { id: 3, name: 'item3' },
      { id: 4, name: 'item4' }
    ]
  },
  methods: {
    removeItems() {
      // item2とitem3を同時に削除
      this.items = this.items.filter(item => item.id !== 2 && item.id !== 3);
    }
  }
});

gyazo.com

これは、以下のような挙動になっているため、このようなトランジションになる。
[item3]は、要素が削除されてから削除された要素が移動する挙動になっている。
[item3]には、[v-leave-active],[v-leave-to]に加えて[v-move]クラスが適用される。
削除された時に[v-leave-to]のopacity 0が適用され、その後の移動の際に[v-move]クラスが適用になるので、opacityが0の状態で移動する。

CSSを以下のいずれかに修正することで意図する挙動となる。

  .v-enter-active, .v-leave-active, .v-move {
    transition: opacity 1s, transform 1s;
  }
  .v-leave-active {
    position: absolute;
  }
  .v-enter, .v-leave-to {
    opacity: 0;
  }

[item3]は、消えた後に移動という挙動になる。
[v-leave-to]クラスでopacityが0になってから移動になるが、[v-move]クラスをここに定義することでopacityが1になる。

  .v-enter-active, .v-leave-active {
    transition: opacity 1s, transform 1s;
  }
  .v-leave-active {
    position: absolute;
  }
  .v-move:not(.v-leave-active) {
    transition: transform 1s;
  }
  .v-enter, .v-leave-to {
    opacity: 0;
  }

[v-leave-actiive]クラスを持っていない時(削除されていない要素)に対してのみ[v-move]を適用する。

gyazo.com