iT邦幫忙

2021 iThome 鐵人賽

DAY 13
0
Modern Web

Vue.js 什麼意思系列 第 13

Day 13:巢狀路由的孩子-Nested Routes

目前設定的 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,
      },
    ];
    

member button

設置會員導覽列與會員項目路由

先為 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,
      },
    ];
    

member nav

此時 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)以「/」開頭的話會被視為根路徑,因此子層路由不需要加上「/」,讓它直接接續父層路徑即可。

設置 redirect 重導向至預設路由

最後,我們希望在點擊會員入口按鈕時,預設一律先導向個人資料頁。做法有很多種,一般可能會先想到處理會員入口按鈕的 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" }

final

巢狀路由的結構有點類似資料夾的分類和層級,因此從路由架構中多少能反映出網站架構,同時也牽涉到元件複用的程度,彼此之間會是互相呼應的狀態。通常一個路由指向一個元件,若是單一元件指向多個路由,就會是巢狀子層路由複用父層元件的情況;又若是單一路由指向多個元件,則是先前介紹過的命名視圖(router-view)出場時機。

參考資料


上一篇
Day 12:Router 繞去哪-active-class & exact-active-class
下一篇
Day 14:動態 Route 對號入座
系列文
Vue.js 什麼意思30

尚未有邦友留言

立即登入留言