Vue 初心者筆記 #30 Vue Router 配置路由與切換元件

本篇筆記介紹 Vue Router 的安裝與配置路由文件,以及如何透過配置文件切換多個元件或分頁。

安裝與配置路由

  • 進入點:main.js
  • Router 配置檔案(前端路由):router/index.js
  • 分頁內容:Vue Components (xxx.vue)

STEP 1:安裝 Vue Router

首先建立一個不包含 Vue Router 的 Vue Webpack 後,輸入 npm install vue-router 安裝 Vue Router。

接著在 /src 下新增 router 資料夾,並在 /router 下新建 index.js 檔案。
這個 index.js 就是放整個路由的配置檔

完成後就載入元件並啟用,而這個配置文件必須能匯出給 Entry 使用

index.js

1
2
3
4
5
6
7
8
9
10
11
12
// 載入官方的元件
import Vue from 'vue';
import VueRouter from 'vue-router';

// 載入自訂的分頁元件
import Home from '@/components/HelloWorld';

// 啟用
Vue.use(VueRouter);

// 匯出給 entry (main.js) 使用
export default new VueRouter({});
  1. @ 是絕對路徑,src 的縮寫
  2. Home 是自定的變數
  3. export default 是 ES6 的模組匯出概念

接著,在 main.js 裡載入配置檔(匯入後由 Router 這個套件來處理),這邊就會載入剛才匯出的配置檔 (index.js) 了。
最後把這個配置檔一樣放在 new Vue({...}) 下運行就可以了。

main.js

1
2
3
4
5
6
7
8
9
10
11
12
import Vue from 'vue';
import App from './App';
import router from './router'; // 載入配置檔

Vue.config.productionTip = false;

new Vue({
el: '#app',
components: { App },
template: '<App/>',
router, // 用擴充的方式加上去
});

STEP 2:定義路徑

接著回到 index.js 定義路徑,定義路徑可以使用 routes 的方式。
這個 routes 的格式是陣列,裡面可以包物件,所以它可以新增很多個路徑與其對應的元件。

1
2
3
4
5
6
7
8
9
10
export default new VueRouter({
// 定義路徑 (routes)
routes: [
{
name: '首頁', // 元件呈現的名稱
path: '/', // 對應的虛擬路徑
component: Home, // 對應的元件
},
],
});

存檔之後會發現畫面沒有任何更動,打開 Vue 的開發者工具也沒有任何變化。
這是因為我們還沒把 Router 要呈現元件的地方放上去。

進到 App.vue,把 <HelloWorld/> 註解掉,新增 <router-view></router-view>
這個 <router-view> 就是我們要呈現元件的地方。

App.vue

1
2
3
4
5
6
7
8
9
<template>
<div id="app">
<img src="./assets/logo.png">
<!-- <HelloWorld/> -->
<router-view></router-view>
</div>
</template>

<!-- omit -->

這時候就能看到變化了。
在 Vue 的開發人員工具裡可以看到 Root/App 下有出現 <router-view>,並呈現 HelloWorld 這個元件。

VueRouter1

路徑會自動加上 # 字號,在這 # 字號以下是虛擬的路由器

STEP 3:修改對應的路徑

如果我們將路徑修改成 path: '/index' 的話,HelloWorld 元件在 http://localhost:8080/#/ 下就不會呈現,它必須對應到 http://localhost:8080/#/index 這個網址時才會出現。

如何透過配置文件切換多個元件

STEP 1:新增分頁元件

在 components 資料夾下,新增 pages 資料夾,並在裡面新增一個新元件 page.vue(資料夾與檔案名稱皆可自訂)。
這個 page.vue 就是我們要做的”分頁”元件,我們先給它一個類似 HelloWorld.vue 的空模板內容就好。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<template>
<div class="hello">
<div class="card" style="width: 18rem;">
<!-- omit -->
</div>
</div>
</template>

<script>
export default {
data() {
return {};
}
};
</script>

STEP 2:配置路徑

接下來我們在路由配置檔 (index.js) 新增 page.vue 的路徑,並且將這個新頁面載入。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// omit...
import Home from '@/components/HelloWorld';
import Page from '@/components/pages/page'; // 載入新的頁面 (Page)
Vue.use(VueRouter);

export default new VueRouter({
routes: [
{
name: '首頁',
path: '/index',
component: Home,
},
{
name: '分頁',
path: '/page',
component: Page,
},
],
});

此時輸入 http://localhost:8080/#/page 可以發現 HelloWorld.vue 的內容會替換成 page.vue 的內容。

STEP 3:透過選單切換分頁

可以透過網址欄輸入網址切換分頁元件後,我們也可以新增選單,透過選單來切換分頁。
因為懶得設計,我就使用 Bootstrap 的 Navbar 來切換分頁唄!
所以第一步就是要把 Bootstrap 加到 index.html 中,這裡就直接用 CDN 加入吧。

1
2
3
4
5
6
7
<head>
<!-- omit -->

<!-- 偷懶用 CDN 加入 Bootstrap -->
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css"
integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous">
</head>

過去都是使用 <a> 標籤的連結,來跳轉至不同的頁面。
但是使用 <a> 連結是跳轉整個頁面,在 Vue CLI 中我們可以使用 <router-link> 來達到只切換內容的效果!

方法一:to + path

<router-view> 切換分頁的第一個方法,是使用 to 加上 path 來切換分頁,步驟如下:

  1. <a> 標籤替換成 <router-link>
  2. href 換成 to

例如:

1
<router-link class="nav-link" to="page">Page</router-link>

方法二::to + name

第二個方法是使用 name 屬性切換分頁,步驟如下:

  1. to 改成動態連接的 :to
  2. 將後面的 path 換成一個物件,裡面是 name 與對應的元件呈現的名稱(e.g. 首頁)

例如:

1
<router-link class="nav-link" :to="{ name: '首頁' }">Home</router-link>

觀念整理

總結來說,我們設置在 App.vue 內的 <router-view></router-view>,就是對應到 router/index.js 內的

1
2
3
4
5
6
7
8
9
10
11
12
routes: [
{
name: '首頁',
path: '/index',
component: Home,
},
{
name: '分頁',
path: '/page',
component: Page,
},
];

因此,router-view 就是顯示 path 所指向的 componet

path:顯示在網址上的路徑
component:指向的元件

巢狀路由 (Nested Routes)

實際應用時,我們除了能切換分頁,也能在同個分頁中切換裡面的組件內容。
概念如下圖所示:

Nested Routes

圖片來源:Nested Routes | Vue Router

透過 Router 切換父路由的卡片內容

STEP 1:修改父路由的模板

我們接續著使用上面創立的分頁 (page.vue),把卡片 (Card) 元件裡的內容替換成 <router-view></router-view>,我們要透過 Router 的方式,切換 Card 裡面的內容。

1
2
3
<div class="card" style="width: 18rem;">
<router-view></router-view>
</div>

STEP 2:新增子路由的模板

接著來我們要新增包在 page.vue 裡面的子元件。
我們把多餘的 <div> 拿掉,只留下一個 <div>,這個 <div> 裡的內容到時候會放在 page.vue 中的 <div class="card" style="width: 18rem;">...</div> 的裡面。

Q:為什麼外層只留一個 <div> 呢?
A:因為組件模板應該只包含一個根元素
在節點樹中,頂端節點被稱為根 (root),所以 <template> 內的頂端的這一個 <div> 就是「根」。
如果把這個 <div> 拿掉,在這個案例中,<img> 以及 <div class="card-body"> 會變成「根」,此時模板內有二個根元素,那就會出現錯誤了。

子模板大致內容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<template>
<div>
<!-- 切換的內容 (外層要留一個 div) -->
<img src class="card-img-top" alt />
<div class="card-body">
<h5 class="card-title">Card 1</h5>
<!-- omit -->
</div>
</template>

<script>
export default {
data() {
return {};
}
};
</script>

STEP 3:配置子路由

完成後到路由配置檔 (index.js) 中配置這些子路徑吧!
首先要先把它們 import 進來:

1
2
3
import Child from '@/components/pages/child';
import Child2 from '@/components/pages/child2';
import Child3 from '@/components/pages/child3';

接著要在分頁的 route 使用 children 配置,加上子元件的路徑,children 的陣列格式就與外層一樣。

超級注意:

  • 移除路徑 (path) 沒有輸入的話,預設路徑在此就會載入卡片 1 元件
  • 依據官方文件說明,巢狀路由第二層以後不用加上 /
    「以 / 開頭的嵌套路徑會被當作根路徑。這讓你充分的使用嵌套組件而無須設置嵌套的路徑。」
    意思就是如果寫 /child2 的話,組件會變成顯示在 http://localhost:8080/#/child2 這個路徑,而非 http://localhost:8080/#/page/child2
  • 因為 Vue router 的設定提示,在有預設子路由的情況之下,實際訪問的是子路由,所以上一級的父路由就不需要設置 name
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
export default new VueRouter({
routes: [
{
name: '首頁',
path: '/index',
component: Home,
},
{
name: '', // 也可以直接把 name 這行註解掉
path: '/page',
component: Page,
children: [
{
name: '卡片 1',
path: '', // 預設路徑
component: Child,
},
// 卡片 2、卡片 3...
],
},
],
});

當然我們也可以透過 <router-link> 來切換組件內容。

1
2
3
<router-link to="/page/">卡片 1</router-link>
<router-link to="/page/child2">卡片 2</router-link>
<router-link to="/page/child3">卡片 3</router-link>

以上資源是我自己整理過後的筆記,若有錯誤歡迎隨時和我聯繫。