跳至主要內容
Skip to content

導航守衛 (Navigation Guards)

想像你的應用程式是一棟大樓,有些房間(路由)是對公眾開放的(首頁、關於我們),但有些房間是需要刷卡才能進入的(會員中心、後台管理)。

Vue Router 的 導航守衛 就是這些門禁系統。它們可以在路由跳轉發生 之前解析時之後 進行攔截。


一、 全域前置守衛 (Global Before Guards)

這是最常見的一種,通常用來檢查使用者是否已登入。

它掛在 router 實體上,對 所有 路由都有效。

javascript
// router/index.js
router.beforeEach((to, from) => {
  // to: 即將要去的路由物件
  // from: 當前正要離開的路由物件

  // 1. 檢查該路由是否需要登入權限
  if (to.meta.requiresAuth && !isAuthenticated()) {
    // 2. 如果沒登入,重導向到登入頁
    // 並帶上 redirect 參數,讓使用者登入後能跳回來
    return {
      path: "/login",
      query: { redirect: to.fullPath },
    };
  }

  // 3. 回傳 undefined 或 true 代表放行
});

TIP

不再需要 next(): 在 Vue Router 3 中,我們必須呼叫 next()。雖然 v4 為了相容性還保留了它,但官方強烈建議直接 return 路由或 false 來控制流程。


二、 路由獨享守衛 (Per-Route Guards)

如果你只想對特定路由做檢查,可以直接寫在 routes 配置裡。

javascript
const routes = [
  {
    path: "/dashboard",
    component: Dashboard,
    beforeEnter: (to, from) => {
      // 只有進入 /dashboard 時才會觸發
      if (!isAdmin()) return "/error";
    },
  },
];

三、 組件內守衛 (In-Component Guards)

這是定義在 .vue 檔案裡的。最常用的是 onBeforeRouteLeave

1. 防止誤觸離開 (Dirty Form Check)

當使用者填寫表單到一半,不小心按了上一頁,我們希望能跳出警告。

html
<script setup>
  import { onBeforeRouteLeave, onBeforeRouteUpdate } from "vue-router";

  // 離開守衛
  onBeforeRouteLeave((to, from) => {
    if (formIsDirty.value) {
      const answer = window.confirm("你有未儲存的變更,確定要離開嗎?");
      // 如果使用者按取消,則回傳 false (阻止跳轉)
      if (!answer) return false;
    }
  });

  // 更新守衛 (當參數改變但組件重用時)
  onBeforeRouteUpdate((to, from) => {
    // id 變了,重抓資料
    fetchData(to.params.id);
  });
</script>

四、 完整的解析流程 (The Full Flow)

這是一個常見的面試題:當你點擊一個連結時,守衛觸發的順序是什麼?

  1. 導航被觸發
  2. 在失活的組件裡呼叫 beforeRouteLeave
  3. 呼叫全域的 beforeEach 守衛。
  4. 在重用的組件裡呼叫 beforeRouteUpdate
  5. 在路由配置裡呼叫 beforeEnter
  6. 解析非同步路由組件。
  7. 在被激活的組件裡呼叫 beforeRouteEnter
  8. 呼叫全域的 beforeResolve 守衛。
  9. 導航被確認
  10. 呼叫全域的 afterEach 鉤子 (這時已無法改變導航)。
  11. 觸發 DOM 更新。
  12. 呼叫 beforeRouteEnter 守衛中傳給 next 的回調函數。

總結

  1. beforeEach: 用於全域權限檢查 (Auth)。
  2. beforeEnter: 針對特定路由的檢查 (Admin)。
  3. onBeforeRouteLeave: 防止資料遺失 (Form)。
  4. onBeforeRouteUpdate: 響應參數變化 (Params)。

下一章,我們將直接跳過 07 (轉場) 與 08 (KeepAlive),因為我們之前已經先行完成了這最困難的兩章!所以我們將進入最後的優化環節:路由懶加載

下一章:深入 RouterView 與頁面轉場 (Transitions)