iT邦幫忙

2021 iThome 鐵人賽

DAY 26
0
Modern Web

不只懂 Vue 語法:Vue.js 觀念篇系列 第 26

不只懂 Vue 語法:試解釋嵌套路由與嵌套命名視圖的概念?

問題回答

嵌套路由是指在一個 router-view 裏包 router-view,像是在一個畫框裏,再加上一個畫框。例如 /products/tshirt/products/shoes,做法可以是在 Product.vue 此頁面元件裏再加一個 router-view,用來切換顯示 Tshirt 與 Shoes 元件。

至於嵌套命名視圖,其實是結合「嵌套路由」和「命名視圖」這兩個概念。前者就是以上提到的意思。後者就是指,當一個畫面要同時顯示多於一 router-view 時,就必須要使用命名視圖(named view)。

結合兩者概念的話,就是指在一個 router-view 裏包 router-view,並在內層的 router-view 裏,再包多於一個的 router-view(需使用命名視圖)。

雖然這題不是常見面試題,但實作時這兩個概念出現的機會挺高。而且作為新手,自己也曾試過搞混了兩者的意思,因此想寫一篇文章來整理概念。

嵌套路由(Nested Routes)是什麼?

嵌套路由較易理解,先看看官方解說圖:

截圖自官方文件

簡單說,就是在一個元件裏放一個 router-view,在這裏可以切換顯示不同的元件。以上例子就是切換 Profile 與 Posts。

為什麼叫嵌套?因為如果你使用 Vue CLI,別忘了最頂層預設已經放了一個 router-view。示範一下,你剛建立 Vue CLI 專案時,會有以下預設程式碼:

App.vue

<template>
  <div id="nav">
    <router-link to="/">Home</router-link> |
    <router-link to="/about">About</router-link>
  </div>
  <router-view/>
</template>

你可以把 nav 刪除,這樣看就更清晰:

<template>
  <router-view/>
</template>

預設路由設定是:

router/ index.js

const routes = [
  {
    path: '/',
    name: 'Home',
    component: Home
  },
  {
    path: '/about',
    name: 'About',
    component: () => import('../views/About.vue')
  }
]

用 Vue 檢查工具看,一目了然:

所以,初始化時,最頂層一定會有一個 router-view,不然沒法顯示元件。這個 router-view 的作用就像一個畫框一樣,你可以隨時切換顯示不同元件,也就是 SPA 的概念:

回到重點,如果在元件裏,再加一個 router-view,並可以切換顯示不同元件,這就是嵌套路由的意思了。白話講,就是在一個畫框裏的元件上,再放一個畫框,切換顯示不同元件。

/about 頁面為例,在 about 頁面加上一個 router-view,切換顯示 SkillsGreetingContact 這三個元件。

About.vue

<template>
  <div class="about">
    <h1>This is an about page</h1>
    <router-link to="/about/greeting"> Greeting</router-link>
    <router-link to="/about/skills"> Skills </router-link>
    <router-link to="/about/contact"> Contact </router-link>
    <router-view></router-view>
  </div>
</template>

使用 children 設定嵌套路由:
router/ index.js

const routes = [
  {
    path: '/',
    name: 'Home',
    component: Home
  },
  {
    path: '/about',
    name: 'About',
    component: () => import('../views/About.vue'),
    children: [
      {
        path: 'skills',
        component: Skills
      },
      {
        path: 'greeting',
        component: Greeting
      },
      {
        path: 'contact',
        component: Contact
      }
    ]
  }
]

然後各自建立 Skills.vue、Greeting.vue、Contact.vue 的檔案,這裏就不示範了。目前 About 裏的的概念如下:

結果就是在 About 元件裏的 Router view 內,可以不斷切換元件:

預設顯示指定嵌套路由

注意,當你進入 /about 頁面,結果會是空的,因為目前是路由是 /about ,並不是 /about/skills/about/greeting 或者 /about/contact。如果想預設顯示某個嵌套路由的元件,舉例說是 Skills,就要把 path 設定為 ''

router/ index.js

  {
    path: '/about',
    name: 'About',
    component: () => import('../views/About.vue'),
    children: [
      {
        path: '',
        component: Skills
      },
      ...
    ]
  }

結果訪問 /about 時,就會渲染 Skill 元件。

嵌套命名視圖(nested named view)是什麼?

了解過嵌套路由,就很快會理解嵌套命名視圖。在這之前,要先知道什麼是命名視圖。當一個畫面裏,我們想設置多於一個 router-view 時,其他 router-view 就需要具名,不然 Vue 不知道這些視圖要放什麼元件。因此,命名視圖就是當畫面上有多於一個 router-view 時,所需要的元素。

以後台 dashboard 為例,在同一個畫面裏,左邊 Sidebar,右邊有 Banner 和 Content。我們在同一個畫面放置 3 個 router-view,其中一個可以不用命名,即是預設 router-view,其餘兩個就要命名。

以上例子就是在 App.vue 放置 3 個 router-view,以下先省略 CSS 部分。

<template>
      <router-view name="Sidebar" />
      <router-view name="Banner" />
      <router-view/>
</template>

router/ index.js

const routes = [
  {
    path: '/',
    components: {
      default: Content,
      Banner,
      Sidebar
    }
  }
]

嵌套命名視圖 = 嵌套路由 + 命名視圖

嵌套命名視圖就是結合以上提到「嵌套路由」、「命名視圖」的概念。再以後台 dashboard 作例子。

假設現在有首頁、產品頁。在產品頁裏,有分 T-shirt 和 Shoes 產品。在 T-shirt 頁裏,用 2 個 router-view 顯示男女裝 T-shirt。而在 Shoes 頁裏,也用 2 個 router-view 顯示 Sneakers 和 Boots。

所以,Product 頁的結構如下:

  • Products.vue 是頁面元件。
  • Sidebar 是在 Product.vue 裏的元件。裏面有 2 個 route-link,分別會連到 products/tshirtproducts/shoes
  • 用預設 router-view(即是匿名 router-view)來顯示 WomenShirt。

詳細程式碼最後才分享,以下先看重點部分。

最外層 App.vue,放置 router-link 以及 router-view,讓使用者切換瀏覽主頁以及產品頁:

<template>
  <router-link to="/"> Homepage </router-link>
  <router-link to="/products"> Products </router-link>
  <router-view />
</template>

點擊 Products 後,進入 Products 頁:

Products.vue

<template>
  <div class="page">
    <Sidebar />
    <div class="content">
      <!-- 當切換到 "/products/tshirt",以下才會顯示-->
      <router-view />
      <router-view name="MenTshirt" />
      <!-- 當切換到 "/products/shoes",以下才會顯示-->
      <router-view name="Sneakers" />
      <router-view name="Boots" />
    </div>
  </div>
</template>

以上畫面中間內容是空,因為現在是在 /products,不是 /products/tshirt 或者 /products/shoes,所以不會顯示這裏的 router-view。當按下 Nav 的按鈕,就能切換顯示相應的 router-view。

看看核心部分 router / index.js

const routes = [
  {
    path: "/",
    component: Home
  },
  {
    path: "/products",
    component: Products,
    children: [
      {
        path: "tshirt",
        components: {
          default: WomenTshirt,
          MenTshirt
        }
      },
      {
        path: "shoes",
        components: {
          Sneakers,
          Boots
        }
      }
    ]
  }
];

以上可見,當切換到 /products/tshirt 時,才會顯示 WomenTshirt 和 MenTshirt。/products/shoes 則會顯示 Sneakers 和 Boots。

完整程式碼

https://codesandbox.io/s/qian-tao-ming-ming-shi-tu-6cbmo?file=/src/App.vue:0-142

總結

  • 嵌套路由是指一個 router-view 裏,再包一個 router-view
  • 當在同一個畫面需要用多於一個 router-view,就需要用命名視圖。
  • 嵌套命名視圖就是結合以上兩者的概念。

參考資料

Vue Router - 嵌套命名视图


上一篇
不只懂 Vue 語法:試解釋 hash 與 history 模式的分別? 為何 history 模式會回傳 404?
下一篇
不只懂 Vue 語法:為何懶加載路由和元件會提升網頁效能?
系列文
不只懂 Vue 語法:Vue.js 觀念篇31

尚未有邦友留言

立即登入留言