跳至主要內容
Skip to content

動態路由與 404 處理

在真實的應用中,我們不可能為每一個使用者都寫死一個路由設定(例如 /user/1, /user/2...)。

我們需要的是一種「模式匹配」,讓 /user/:id 能夠對應到同一個組件,但根據不同的 ID 顯示不同的資料。這就是 動態路由 (Dynamic Route Matching)


一、 帶參數的路由 (Params)

在定義 path 時,使用冒號 : 開頭的段落就會被視為參數。

javascript
const routes = [
  // 動態段以冒號開始
  { path: "/users/:id", component: User },
];

當網址是 /users/123 時:

  • User 組件會被渲染。
  • route.params 會包含 { id: '123' }

在組件中獲取參數

html
<!-- User.vue -->
<template>
  <div>User ID: {{ route.params.id }}</div>
</template>

<script setup>
  import { useRoute } from "vue-router";

  const route = useRoute();
  console.log(route.params.id);
</script>

你可以在一個路徑中設置多個參數:

模式匹配路徑$route.params
/users/:username/users/evan{ username: 'evan' }
/users/:username/posts/:postId/users/evan/posts/123{ username: 'evan', postId: '123' }

二、 響應參數變化 (Reactivity)

這是一個新手常踩的坑。

當你從 /users/1 導航到 /users/2 時,原本的組件實體會被重複使用 (Recycled),而不會被銷毀重建。這是為了效能考量。

但這也意味著組件的生命週期 hooks (如 onMounted) 不會再次被呼叫。如果你在 onMounted 裡發送 API 請求,切換 ID 時資料就不會更新。

解決方案 1:監聽 params

javascript
import { watch } from "vue";
import { useRoute } from "vue-router";

const route = useRoute();

// 監聽 id 變化
watch(
  () => route.params.id,
  (newId, oldId) => {
    // 當 ID 改變時,重新抓取資料
    fetchUserData(newId);
  },
);

解決方案 2:onBeforeRouteUpdate 守衛

Vue Router 4 提供了組件內的導航守衛,這也是推薦的做法:

javascript
import { onBeforeRouteUpdate } from "vue-router";

onBeforeRouteUpdate((to, from) => {
  // 對,params 變了
  if (to.params.id !== from.params.id) {
    fetchUserData(to.params.id);
  }
});

三、 捕獲所有路由 (404 Not Found)

一般的路由是由上而下匹配的。如果所有的路由都沒配對成功,使用者就會看到一片空白。我們通常會在最後加一個「萬用路由」來顯示 404 頁面。

在 Vue Router 4 中,語法與以前不同,必須使用 正則表達式 的語法:

javascript
const routes = [
  { path: "/", component: Home },
  { path: "/about", component: About },

  // 舊版 v3 寫法: '*' (在 v4 已移除)
  // 新版 v4 寫法: 使用正則 (.*)
  { path: "/:pathMatch(.*)*", name: "NotFound", component: NotFound },
];
  • :pathMatch: 參數名稱 (你可以改叫 :afterUser 之類的)。
  • (.*): 正則表達式,代表匹配任意字元。
  • *: 代表重複零次或多次 (這讓 / 也能被匹配到,如果沒加這個星號,/ 可能會報錯或匹配不到)。

當路由配對到這行時,route.params.pathMatch 會包含使用者輸入的路徑陣列。


四、 進階匹配語法

有些時候我們對參數有更嚴格的限制。例如 id 必須是數字。

限制參數格式

你可以在參數後面的括號中加入正則:

javascript
const routes = [
  // 只有當 id 是數字時才匹配
  // /users/123 -> 匹配
  // /users/abc -> 不匹配 (繼續往下找,可能找到 404)
  { path: "/users/:id(\\d+)", component: User },
];

這在區分 /users/create (建立新用戶) 與 /users/:id (查看用戶) 時非常有用。


總結

  1. 用冒號 : 定義動態參數。
  2. route.params 讀取參數。
  3. 注意組件重用問題:使用 watchonBeforeRouteUpdate 來響應變化。
  4. /:pathMatch(.*)* 來實作 404 頁面。

下一章,我們將介紹 Vue Router 最強大的功能之一:巢狀路由 (Nested Routes),這是建構複雜 Dashboard 介面的核心技巧。

下一章:巢狀路由 (Nested Routes)