跳至主要內容
Skip to content

深入 RouterView 與頁面轉場 (Transitions)

在 Vue 2 的時代,我們可以簡單地把 <router-view> 包在 <transition> 裡面。但在 Vue 3,這一切變了。

為什麼?因為 router-view 不再是一個單純的組件,它變成了一個「插槽容器 (Slot Container)」。

這一章,我們將解開 v-slot 的奧秘,並實現各種炫砲的轉場效果。


一、 為什麼寫法變了?

在 Vue 2:

html
<!-- Vue 2 (已過時) -->
<transition>
  <router-view></router-view>
</transition>

在 Vue 3 (Vue Router 4),如果你這樣寫,console 會噴黃字警告,而且動畫不會生效。正確的寫法是:

html
<!-- Vue 3 標準寫法 -->
<router-view v-slot="{ Component }">
  <transition name="fade" mode="out-in">
    <component :is="Component" />
  </transition>
</router-view>

這裡發生了什麼事?

  1. v-slot="{ Component }": RouterView 會把它「當前匹配到的組件」透過 Slot Props 傳出來。
  2. <component :is="Component">: 我們拿到這個組件,手動把它渲染出來。
  3. <transition>: 因為我們現在手握組件實體,所以可以自由地包在 transition (或 keep-alive) 裡面。

這種設計雖然囉嗦,但給了我們極大的靈活性。以前我們很難對不同的路由做不同的處理,現在因為多了一層 Slot,我們可以拿到 route 對象做判斷。


二、 基礎轉場 (Fade Effect)

最常見的「淡入淡出」效果。

Template

html
<router-view v-slot="{ Component }">
  <transition name="fade" mode="out-in">
    <component :is="Component" />
  </transition>
</router-view>

CSS

css
.fade-enter-active,
.fade-leave-active {
  transition: opacity 0.5s ease;
}

.fade-enter-from,
.fade-leave-to {
  opacity: 0;
}
  • mode="out-in": 這非常重要!它讓舊組件「先消失 (Out)」,新組件「再出現 (In)」。如果不加這個,你會看到兩個頁面同時存在一瞬間,版面會亂跳。

三、 動態轉場 (Dynamic Transitions)

如果我想讓「進入內頁」時向左滑,「回到上一頁」時向右滑,該怎麼做?

我們可以利用 Route Meta 來告訴 Router 該用哪個動畫。

1. 定義 Meta

router/index.js 中:

javascript
const routes = [
  {
    path: "/",
    component: Home,
    meta: { transition: "slide-left" }, // 自定義欄位
  },
  {
    path: "/about",
    component: About,
    meta: { transition: "slide-right" },
  },
];

2. 在 RouterView 中使用

html
<router-view v-slot="{ Component, route }">
  <!-- 使用 route.meta.transition 作為 name -->
  <transition :name="route.meta.transition || 'fade'" mode="out-in">
    <component :is="Component" />
  </transition>
</router-view>

四、 進階:基於路由深度的轉場

上面的方法還是得手動寫死。更聰明的做法是:比較 tofrom 的層級深度

javascript
// router.afterEach 用來動態計算動畫
router.afterEach((to, from) => {
  const toDepth = to.path.split("/").length;
  const fromDepth = from.path.split("/").length;

  if (toDepth < fromDepth) {
    to.meta.transition = "slide-right"; // 回上一層 -> 向右滑
  } else if (toDepth > fromDepth) {
    to.meta.transition = "slide-left"; // 進下一層 -> 向左滑
  } else {
    to.meta.transition = "fade"; // 同層級 -> 淡入淡出
  }
});

總結

Vue Router 4 的 <router-view> 改用 Slot API 是一個巨大的進步,它解鎖了無限的可能性。

  1. 必須使用 v-slot: <router-view v-slot="{ Component }">
  2. 動態組件渲染: <component :is="Component">
  3. 模式選擇: 大多數情況下請加上 mode="out-in"

理解了這個結構,下一章我們要挑戰最艱難的任務:<keep-alive> 也加進去

下一章:狀態緩存的藝術:KeepAlive