🤖
Vue RouterとTransitionで画面遷移の実装したときにハマった
はじめに
Vue RouterとVueのビルトインコンポーネントであるTransitionで画面遷移時のアニメーションを適用することにした。
しかし、一部のコンポーネントの読み込みが以上に遅くなってしまったので、調査〜解決まで行ってみた。
TL;DR
<Transition>
は子要素として単一ノードでなければならない。
<component>
を<div>
で囲って一つの要素にする必要があった。
ただ、<Transition>
のアニメーションを発火させるため、<div>
にkey
属性を追加する必要がある。
Transitions require single children nodes. Therefore you can wrap the
<component>
tag inside a<div>
, however, a plain<div>
inside a<transition>
won't trigger the transition, but changing the key attribute does.
開発環境
- PC
- MacBook Pro
- macOS(Sonoma)
- フレームワーク・ライブラリ
- Vue
- 3.2.37
- Vue Router
- 4.1.6
- Vite
- 3.1.0
- TailwindCSS
- 3.2.1
- Vue
ソース
BEFORE
App.vue
<template>
<div class="h-screen">
<RouterView
name="Header"
v-slot="{ Component }"
>
<Transition
mode="out-in"
enter-active-class="transition-opacity"
leave-active-class="transition-opacity"
enter-from-class="opacity-0"
leave-to-class="opacity-0"
>
<component :is="Component" />
</Transition>
</RouterView>
<RouterView v-slot="{ Component }">
<Transition
mode="out-in"
enter-active-class="transition-opacity"
leave-active-class="transition-opacity"
enter-from-class="opacity-0"
leave-to-class="opacity-0"
>
<component :is="Component" />
</Transition>
</RouterView>
</div>
</template>
<script setup lang="ts">
import { RouterView } from 'vue-router'
</script>
AFTER
App.vue
<RouterView
name="Header"
- v-slot="{ Component }"
+ v-slot="{ Component, route }"
>
<Transition
mode="out-in"
enter-active-class="transition-opacity"
leave-active-class="transition-opacity"
enter-from-class="opacity-0"
leave-to-class="opacity-0"
>
+ <div :key="route.fullPath">
+ <component :is="Component" />
+ </div>
</Transition>
</RouterView>
やったこと
-
<RouterView>
に渡しているv-slot
にroute
を追加- 後述する囲い
<div>
のkey
属性に渡すユニークな値としてroute.fullPathを使用 - ちなみに
<RouterView>
にv-slot
を渡していることに関してはこちら
- 後述する囲い
-
<component>
を<div>
で囲い、<Transition>
内で単一の子要素を作る
結果
BEFORE
遷移時にもヘッダーが常に表示され、メインコンテンツの表示に遅延が発生している
AFTER
まとめ&感想
最近まで画面遷移時のアニメーションなど今まで実装してなかったり、考えてもこなかったんですが、Vueの<Transition>
を使ってみてUXが大分良くなったなぁって感じました。
あと、今回のバグ直す時に他の人は自分と違って名前付きビューで実装してなかったので、地味に時間かかりました。。
もし、間違ってたりもっと良い実装方法があれば教えてください!
Discussion