Vue.jsのtransition-groupの使い方

Vue.js

Vue.jsのtransition-groupコンポーネントの使い方をまとめました。

transition-groupを使う場面

<ul>
  <li v-for="todo in todos" :key="todo.id" @click="deleteTodo(todo.id)">
    {{ todo.text }}
  </li>
</ul>

たとえば、上のような例では、v-forでlistタグが複数作成されます。
このような場面では、transitionコンポーネントは使えないため、transition-groupコンポーネントを使います。
transitionコンポーネントが使えない理由は、transitionコンポーネントの使い方を確認してみてください。

transition-groupの具体例

<transition-group tag="ul" name="list">
  <li v-for="todo in todos" :key="todo.id" @click="deleteTodo(todo.id)">
    {{ todo.text }}
  </li>
</transition-group>

上のように、まずは、transition-groupで囲みます。
そして、ulタグの代わりに利用しているので、タグが何であるか明示的に示す必要があります。
上の場合ulタグなので、tag="ul"とします。
そして、name属性を付与します。

後は、transitionコンポーネントと同じ使い方となります。

appear属性(作成時)

ノードの初期描画時にトランジションを適用したい場合は、appear属性を付与します。

<transition-group appear tag="ul" name="list">
  <li v-for="todo in todos" :key="todo.id" @click="deleteTodo(todo.id)">
    {{ todo.text }}
  </li>

リロードするとふわっと出てくるようなアニメーションを確認できます。
カスタマイズする場合は、公式サイトを確認するのがわかりやすいです。

move-class属性(削除時)

削除したときも同じようにふわっと消えるようなアニメーションを付与したい場合は、move-class属性を使います。
ulタグにpositionのrelativeを設定してしているのであれば、次のように記述します。

ul {
    position: relative;
  }
.list-leave-active {
  transition: all 0.3s ease;
  position: absolute;
}

.list-move {
  transition: all 0.3s ease;
}

v-ifとv-elseにもtransitionを設定したい場合

v-ifとv-elseといった条件が異なる場合において、両方の場合でtransitionを適用したい場合があります。
たとえば次のようなケースです。

      <div v-if="todos.length">
        <transition-group tag="ul" name="list" appear>
          <li v-for="todo in todos" :key="todo.id" @click="deleteTodo(todo.id)">
            {{ todo.text }}
          </li>
        </transition-group>
      </div>
      <div v-else>todoがありません。</div>

todoがある場合とない場合でメッセージを変える、といった場合があります。

上の状態では、transition-groupで囲われている部分しかtransitionが適用されません。

このような場合、次のようにします。

transitionで囲む

<transition name="switch">
  <div v-if="todos.length">
    <transition-group tag="ul" name="list" appear>
      <li v-for="todo in todos" :key="todo.id" @click="deleteTodo(todo.id)">
        {{ todo.text }}
      </li>
    </transition-group>
  </div>
  <div v-else>todoがありません。</div>
</transition>

上のように、v-ifとv-elseを含めてtransitionコンポーネントで囲います。
それに名前をつけて、transitionを適用します。

上の場合はnameをとしています。

<style scoped>

.switch-enter-from,
.switch-leave-to {
  opacity: 0;
  transform: translateY(40px)
}

.switch-enter-to,
.switth-leave-from {
  opacity: 1;
  transform: translateY(0)
}

.switch-enter-active,
.switch-leave-active {
  transition: all 0.3s ease-in-out;
}</style>

上の場合、真ん中のenter-toとleave-fromはデフォルトの設定と同じため、なくても大丈夫です。

ただし、これだけではメッセージの切り替わるタイミングで両方が同時に表示される場面があるため、カクつきます。
そこで次のように設定します。

modeを設定する

<transition name="switch" mode="out-in">
  <div v-if="todos.length">
    <transition-group tag="ul" name="list" appear>
      <li v-for="todo in todos" :key="todo.id" @click="deleteTodo(todo.id)">
        {{ todo.text }}
      </li>
    </transition-group>
  </div>
  <div v-else>todoがありません。</div>
</transition>

上にさらにmodeを付け足すことで、スムーズなトランジションが出来上がります。
modeはout-inとin-outが選択できます。
out-inはメッセージが消えてから次のものが現るというもので、in-outはその逆です。
上の場合、リストのアイテムを削除したあとに、メッセージを表示したいので、out-inを選択しています。

Vue.js

Posted by devsakaso