Vue Router 巢狀路由:打造高效的頁面版面配置與局部切換機制
在開發複雜的網頁應用時,我們經常會遇到 頁面外殼不變,僅局部內容切換 的需求,例如:會員中心、後台管理系統。這時 巢狀路由 (Nested Routes) 就是您的最佳工具。
為什麼需要巢狀路由?
巢狀路由允許我們在父路由元件內部定義子路由,並在特定位置渲染子頁面。
- 程式碼複用:不需要在每個子頁面重複撰寫相同的導覽列、側邊欄或頁尾。
- 狀態保持:切換子路由,例如:從 個人資料 切換到 訂單列表 )時,父元件(外殼)不會被銷毀重洗,能保持原有的輸入狀態或滾動位置。
規劃檔案架構
以 會員中心 為實體,我們將頁面拆分為一個父元件與兩個子元件:
src/
├─ router/
│ └─ index.js # 路由核心配置
├─ views/
│ ├─ member/ # 存放子頁面
│ │ ├─ Profile.vue # 子頁面:個人資料
│ │ └─ Orders.vue # 子頁面:訂單列表
│ ├─ Member.vue # 父頁面:外殼
│ └─ ...
├─ App.vue
└─ main.js父元件配置:準備 <router-view />
父元件 Member.vue 扮演的是 Layout(版面配置)的角色,它決定了子頁面要顯示在哪裡。
Member.vue
<template>
<h1>會員中心</h1>
<router-link to="/member/profile">個人資料</router-link>|
<router-link to="/member/orders">訂單列表</router-link>
<RouterView />
</template>子頁面沒出現?先檢查這裡
巢狀路由最常見的問題就是 父元件忘了放 <router-view />。子路由的元件是渲染在父元件的 <router-view /> 位置,父層沒有這個標籤,路由雖然切換成功,畫面上卻什麼都不會變。
此時整個應用程式會有 兩層 <router-view />:App.vue 那一層負責顯示 Member.vue,Member.vue 這一層負責顯示 Profile.vue 或 Orders.vue。
子元件配置
這兩個元件會被渲染在父頁面的 <router-view /> 位置。
Profile.vue
<template>
<h3>會員個人資料</h3>
</template>Orders.vue
<template>
<h3>訂單歷史紀錄</h3>
</template>路由表設定:使用 children 屬性
在路由設定檔中,我們利用 children 陣列來定義層級關係。注意:子路由的 path 通常不需要加斜線 /。如果加了 / 會被視為從根目錄開始。
import { createRouter, createWebHistory } from 'vue-router';
export default createRouter({
history: createWebHistory(),
routes: [
{
path: '/',
name: 'home',
component: () => import('@/views/Home.vue'),
},
{
path: '/about',
name: 'about',
component: () => import('@/views/About.vue'),
},
{
path: '/product/:id',
name: 'product',
component: () => import('@/views/Product.vue'),
},
{
path: '/member',
component: () => import('@/views/Member.vue'),
children: [
{
// 當路徑為 /member 時,自動重新導向至 profile
path: '',
name: 'member',
redirect: '/member/profile',
},
{
// 注意:子路由 path 通常不加 /,會自動串接在父層之後
path: 'profile',
name: 'member-profile',
component: () => import('@/views/member/Profile.vue'),
},
{
// 注意:子路由 path 通常不加 /,會自動串接在父層之後
path: 'orders',
name: 'member-orders',
component: () => import('@/views/member/Orders.vue'),
},
],
},
{
path: '/:pathMatch(.*)*',
redirect: '/',
},
],
});關鍵規則與開發細節
子路由 Path 的斜線問題
path: 'profile'(不加斜線):網址會自動拼接為/member/profile。path: '/profile'(加斜線):會被視為 根路徑,網址會變成/profile而非/member/profile,雖然它依然是Member.vue的子路由。建議子層路徑統一 不加斜線 以保持結構語意。
預設子頁面的兩種寫法
進入 /member 時總得顯示點東西,常見有兩種做法:
// 寫法一:導向指定的子路由(網址會變成 /member/profile)
{ path: '', redirect: '/member/profile' }
// 寫法二:直接指定預設元件(網址維持 /member)
{ path: '', name: 'member', component: () => import('@/views/member/Profile.vue') }想讓網址明確反映目前分頁就用第一種;希望網址保持簡短則用第二種。
具名路由的建議
通常在開發巢狀路由時,建議把 name: 'member' 從父層拿掉或移到子層,因為訪問 /member 時,它會立刻跳轉到 /member/profile,這時父層的 name 其實很少被直接用到。亦可移除因為導向父路由名稱時,系統不確定要停在父層還是直接進入預設子層的警告。
父元件不會被重建
這是巢狀路由最實際的好處:子路由切換時,父元件不會被銷毀,所以側邊欄的展開狀態、捲軸位置與已經取回的資料都會保留。若父元件在 onMounted 抓過會員基本資料,切換分頁時不會重複請求。
搭配權限控管
會員中心這類頁面通常需要登入才能進入。由於 to.meta 會 自動合併父層與子層,只要在父路由加上一次標記,底下所有子頁面都會受到保護:
{
path: '/member',
component: () => import('@/views/Member.vue'),
meta: { requiresAuth: true },
children: [ /* 略 */ ],
}完整的驗證流程請看 導航守衛。若多個子頁面需要共用會員資料,則適合交給 Pinia 保存。
總結
巢狀路由是 Vue 開發中處理 Layout 版面配置的核心。透過 children 配置與 <router-view /> 的嵌套,您能輕鬆構建出層級分明、易於維護的 SPA 應用程式。
常見問題
子路由的 path 要不要加斜線?
不要加。寫 profile 會自動串接成 /member/profile;寫成 /profile 會被當成根路徑,網址變成 /profile。建議子層統一不加斜線以保持層級語意。
為什麼子頁面沒有顯示出來?
最常見的原因是父元件忘記放 <router-view />。子路由的元件是渲染在父元件的 <router-view /> 位置,父層沒有這個標籤就沒有地方顯示。
進入父路由時要怎麼顯示預設子頁面?
在 children 裡加一筆 path 為空字串的路由,用 redirect 導向想要的子頁面,或直接指定 component 當作預設頁。
切換子路由時父元件會被重建嗎?
不會。父元件會保留在畫面上,因此側邊欄的展開狀態、捲軸位置與已載入的資料都不會重置,這也是巢狀路由最大的好處。
巢狀路由可以做幾層?
層數沒有硬性限制,只要每一層的元件都放了 <router-view /> 就能繼續往下嵌套。但層級過深會讓路由表難以閱讀,實務上多數專案兩到三層就足夠。