目前設定的 Navbar 路由架構還算單純,並且只有單層路徑,但是當專案規模愈來愈大、功能類別拆分的愈趨詳細時,整體網站就相對需要更具層級性的規劃,此時路由架構就得跟著使用巢狀設置來因應需求。本篇就來壯大一下專案規模,許願一個新需求:
直接套用 BootstrapVue 的 Button 元件,加在 Navbar 元件 <b-collapse> 中的最後一個項目(顯示在畫面右上角);同時增加一個 MemberPage 元件作為會員頁面的 layout,讓點擊會員入口按鈕時能夠導向 MemberPage 頁面。
Navbar.vue
<b-button
variant="primary"
size="sm"
class="my-2 my-sm-0"
type="button"
@click="$router.push('/member').catch((error) => error)"
>會員</b-button>
router/index.js
import MemberPage from "@/components/MemberPage.vue";
const routes = [
...
{
path: "/member",
name: "MemberPage",
component: MemberPage,
},
];
先為 MemberPage 增加一個會員專用的導覽列,點選會員導覽項目時會再導向其各自的路徑,另外也為導覽項目各自新增其對應的 .vue 元件檔案。
然後別忘了要加上 <router-view>,才能因應路由切換而顯示匹配路徑的元件內容喔!
MemberPage.vue
<div class="MemberPage">
<div class="tabs">
<router-link
v-for="tab in tabs"
:key="tab.id"
:to="tab.path"
class="tab"
>{{ tab.item }}</router-link
>
</div>
<router-view />
</div>
data() {
return {
tabs: [
{
id: 0,
item: "個人資料",
path: "/profile",
},
{
id: 1,
item: "收藏紀錄",
path: "/collection",
},
],
};
},
router/index.js
import MemberPage from "@/components/MemberPage.vue";
import Profile from "@/views/Profile.vue";
import Collection from "@/views/Collection.vue";
const routes = [
...
{
path: "/member",
name: "MemberPage",
component: MemberPage,
},
{
path: "/profile",
name: "Profile",
component: Profile,
},
{
path: "/collection",
name: "Collection",
component: Collection,
},
];
此時 MemberPage 確實有了會員導覽列,但是當我點選會員導覽項目時,會員導覽列卻不見了?這是因為我們的路由路徑不能像之前一樣只設置單層,而是要讓會員導覽項目隸屬於會員導覽列之下。
如果只是將會員導覽項目路徑改成「/member/profile」的形式還是不可行的,雖然初步展現出層級,但會員導覽列仍僅限在 MemberPage 元件中使用,這時候正是使用巢狀路由的時機了!
設置巢狀路由的方法很簡單,只要劃分好父層和子層的相對關係,將共用元件放在父層提供給子層 children 共享即可。讓我們再來重新改寫路由架構:
// router/index.js
import MemberPage from "@/components/MemberPage.vue";
import Profile from "@/views/Profile.vue";
import Collection from "@/views/Collection.vue";
const routes = [
...
{
path: "/member",
component: MemberPage,
children: [
{
path: "profile",
name: "Profile",
component: Profile,
},
{
path: "collection",
name: "Collection",
component: Collection,
},
],
},
];
這裡需要特別留意的是,若巢狀路由(children path)以「/」開頭的話會被視為根路徑,因此子層路由不需要加上「/」,讓它直接接續父層路徑即可。
最後,我們希望在點擊會員入口按鈕時,預設一律先導向個人資料頁。做法有很多種,一般可能會先想到處理會員入口按鈕的 click 事件:
@click="$router.push('/member/profile')
@click="$router.push({ name: 'Profile' })
當然還有個更方便的作法,就是直接設定 redirect
。click 事件一樣維持為 @click="$router.push('/member')
不用改動,只需要在 /router/index.js 中指定好預設路由即可,處理起來更直覺了吧!
redirect: "/member/profile"
redirect: { name: "Profile" }
巢狀路由的結構有點類似資料夾的分類和層級,因此從路由架構中多少能反映出網站架構,同時也牽涉到元件複用的程度,彼此之間會是互相呼應的狀態。通常一個路由指向一個元件,若是單一元件指向多個路由,就會是巢狀子層路由複用父層元件的情況;又若是單一路由指向多個元件,則是先前介紹過的命名視圖(router-view)出場時機。