0%

Vue Router筆記

使用Vue Router 及配置路由文件

user頁面
product頁面
以上範例,你可以看到它們都是停留在index的網址上,
但是,會因為我們在#後面所接入的內容不同,來呈現不同元件的內容。
像上面圖片是#/user,所以,此時是呈現 user 元件。
像下面圖片是#/product,所以,此時是呈現 product 元件。

故本節是紀錄怎麼建立Vue Router

Router會包含幾個檔案

首先,進入點
包含它會注入src資料夾中的元件檔和其他的component檔案。

第二,新增路由的配置檔案
這個配置檔案會決定在哪個路由中呈現哪個元件檔案。
那它執行的路徑會在router/index.js 中。

第三,分頁內容

Vue Components 就是一些元件的檔案,例如專案檔中的Hellowolrd.vue檔。

接下來,介紹安裝vue 的router步驟
step1.
先輸入 npm install vue-router --save 指令

step2.
在src資料夾中,新建一個叫router的資料夾
在router下再新增一個叫index.js的檔案,這個檔案就是要放整個路由的配置檔。

step3.
在index.js檔案中輸入
import Vue from 'vue'
import VueRouter from 'vue-router'

以上這兩行呢,是將官方提供的元件給引入進來。

接下來,在這兩行之後就是引入我們自己的元件囉。
import Home from '@/component/HelloWorld'
引入在src資料夾中的HelloWorld元件檔,並將它命名為Home

step4.
在你引入完官方元件 和你自己的元件檔之後,
就是要輸入啟用的指令,
那你就在同一個index.js檔案中,在引入程式碼的後方輸入Vue.use(VueRouter)
ex:

1
2
3
4
5
6
7
import Vue from 'vue'
import VueRouter from 'vue-router'

// 以上為官方提供的元件
import Home from '@/component/HelloWorld'

Vue.use(VueRouter) // 啟用指令

step5.
因為這個檔案,我們必須匯出給entry使用,
所以,我們要再加上以下的程式碼

1
2
3
4
5
6
7
8
9
10
import Vue from 'vue'
import VueRouter from 'vue-router'

// 以上為官方提供的元件
import Home from '@/components/HelloWorld'

Vue.use(VueRouter)

export default new VueRouter({
});

你可以看到我們在最下面,輸入了export的相關內容。

step6.
在main.js檔案中,匯入你的router檔案

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
---main.js檔案---
// The Vue build version to load with the `import` command
// (runtime-only or standalone) has been set in webpack.base.conf with an alias.
import Vue from 'vue'
import App from './App'
import axios from 'axios'
import VueAxios from 'vue-axios'
import router from './router' // 匯入router檔案

Vue.use(VueAxios, axios)
Vue.config.productionTip = false

/* eslint-disable no-new */
new Vue({
el: '#app',
components: { App },
template: '<App/>',
router, // 新增router屬性
})

你可以看到我們在main.js檔案中匯入了router檔案,
並在vue物件新增了一個router屬性

step7.
運行npm run dev 來執行vue的環境吧
此時,你運行http://localhost:8080
應該會發現你的網址後面新增了#,而這個#後面就是你的虛擬路由器

step8.
接著,你就去index.js中的export default new VueRouter內容新增以下的內容
ex:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import Vue from 'vue';
import VueRouter from 'vue-router';

// 以上為官方提供的元件
import Home from '@/components/HelloWorld'

Vue.use(VueRouter);

export default new VueRouter({
routes:[
{
name:'首頁',//元件呈現名稱
path:'/', //對應虛擬的路徑
component:Home , //它所對應的原件
}
]
});

step9.
接著你去App.vue檔案中的template部分,
新增以下的<router-view></router-view>
並把原本的<Helloworld>元件的部分註解掉

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

接著,你在畫面上應該是看不出來有啥差別,此時,你就打開vue開發者工具,
你去看App底下的HelloWolrd元件的標籤旁邊,應該就會跟著一個router-view的標籤喔。

接下來我們要新增另一個元件,

step1.
接著,我們先偷懶在最外層的index.html引入bootstrap的CSS的CDN。

step2.
我們在components資料夾中,新增一個pages的資料夾
在這個pages資料夾中新增一個pages.vue的元件檔

step3.
我們去bootstrap中的card元件內容複製,並貼到pages.vue的template中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<template>
<div>
<div class="card" style="width: 18rem;">
<img src="" class="card-img-top" alt="...">
<div class="card-body">
<h5 class="card-title">Card title</h5>
<p class="card-text">Some quick example text to build on the card title and make up the bulk of the card's content.</p>
<a href="#" class="btn btn-primary">Go somewhere</a>
</div>
</div>
</div>
</template>

<script>
export default {
name: 'pages',
data () {
return{

}
}
}
</script>

以上的內容你就可以看到,我們在pages中的template加入了card元件的內容。

注意,元件外面要再包一個div

老師建議,你在創任何元件的template的時候,它們的內容外面都要再包一層div
是因為Vue 最外層的元素不能直接使用 vue 的指令。
ex:

1
2
3
<template>
<div v-for="..."></div>
</template>

像上面這樣,如果你直接對最外層使用v-for指令的話,就會出錯喔。

step4.
接著,你去index.js檔案裡面,新增引入pages元件的相關設定

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import Vue from 'vue';
import VueRouter from 'vue-router';

import Home from '@/components/HelloWorld'
import Page from '@/components/pages/pages' // 引入pages.vue元件

Vue.use(VueRouter);

export default new VueRouter({
routes:[
{
name:'首頁',
path:'/index',
component:Home ,
},
{ // 新增pages元件的相關設定
name:'分頁',
path:'/page',
component:Page ,
}
]
});

step5.
接著,你將你的vue的網址的#號後面,加入Page
即:
http://localhost:8080/#/Page

此時,你應該就可以看到在網頁上看到新增的 Page 元件的內容。

製作分頁的切換

接下來要接分頁的切換
step1.
首先我們先為 App.vue 元件檔引入 bootstrap 的 navbar 內容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
---App.vue 元件檔---
<template>
<div id="app">
<!--navbar開始-->
<nav class="navbar navbar-expand-lg navbar-light bg-light">
<div class="container-fluid">
<a class="navbar-brand" href="#">Navbar</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
<li class="nav-item">
<a class="nav-link active" href="#">Home</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">Page</a>
</li>
</ul>
</div>
</div>
</nav>
<!--navbar結束-->

<img src="./assets/logo.png">
<router-view></router-view>
<button class="btn btn-danger">按鈕</button>
</div>
</template>

你可以看到,我們在template中,加入了navbar樣式,此時,你刷新網頁後,
應該就會出現navbar的樣式了。

step2.
接著,我們修改在App.vue的檔案中,連動到Home和Page的a標籤,將其改成router-link標籤,並在這些標籤內分別加入to="/index"和to="/Page"

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
---APP.vue檔案---
<template>
<div id="app">
<nav class="navbar navbar-expand-lg navbar-light bg-light">
<div class="container-fluid">
<a class="navbar-brand" href="#">Navbar</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
<li class="nav-item">
<router-link class="nav-link active" to="/index">Home</router-link> // 轉換到 Home 的按鈕
</li>
<li class="nav-item">
<router-link class="nav-link" to="/Page">Page</router-link> // 轉換到 Page 的按鈕
</li>
</ul>
</div>
</div>
</nav>

<img src="./assets/logo.png">
<router-view></router-view>
<button class="btn btn-danger">按鈕</button>
</div>
</template>

此時,你點擊 Home 和 Page 按鈕的時候,應該就跳轉到 Home 或 Page 的頁面囉,所以,在 index.js 中,各物件的 path 屬性,就是用在跳轉分頁路徑做使用。

除了to以外,還有其他跳轉頁面的方法

就是使用在index.js中,你為那些元件檔所加入的name的屬性名稱。
所以,就將App.vue中的navbar做以下的修改

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<template>
<div id="app">
<nav class="navbar navbar-expand-lg navbar-light bg-light">
<div class="container-fluid">
<a class="navbar-brand" href="#">Navbar</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
<li class="nav-item">
<router-link class="nav-link active" :to="{name:'首頁'}">Home</router-link> // 換成name的屬性名稱
</li>
<li class="nav-item">
<router-link class="nav-link" to="/Page">Page</router-link>
</li>
</ul>
</div>
</div>
</nav>

<img src="./assets/logo.png">
<router-view></router-view>
<button class="btn btn-danger">按鈕</button>
</div>
</template>

你可以看到,在首頁的router-link標籤部分,我們把to的屬性用v-bind去動態綁定name屬性,並將這個屬性名稱改成這個元件的name的名稱,如此,就可以跟原本的to達成一樣的切換頁面效果囉。

製作巢狀路由頁面

首先,我們在pages同一層的目錄中,分別建立三個元件檔child.vue, child2.vue, child3.vue
接著,你要特別注意一點,
在這三個元件檔child.vue, child2.vue, child3.vue中的card元件是不包含最外層的card。
那在pages檔案中,就只有保留最外層的.card的div
因為,我們希望透過切換child.vue, child2.vue, child3.vue 來變換pages.vue中,.card裡面的內容。
所以,要改成像下面這樣
即:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
---child.vue檔案---
<template>
<div>
<img src="" class="card-img-top" alt="...">
<div class="card-body">
<h5 class="card-title">Card 1</h5>
<p class="card-text">Some quick example text to build on the card title and make up the bulk of the card's content.</p>
<a href="#" class="btn btn-primary">Go somewhere</a>
</div>
</div>
</template>


---pages.vue檔案---
<template>
<div>
<div class="card" style="width: 18rem;">
<router-view><router-view>
</div>
</div>
</template>

你可以看到,我們在pages的元件裡面,在想要替換內容的部分,加入<router-view></router-view>,藉此,透過router的方式,來變換card.vue, card2.vue, card3.vue的內容。

step2.
我們回到index.js檔案中,
我們先將child.vue, child2.vue, child3.vue 這三個元件檔引入到index.js檔案裡面。

1
2
3
import child_1 from '@/components/pages/child' 
import child_2 from '@/components/pages/child2'
import child_3 from '@/components/pages/child3'

step3.
在pages的元件內容中,加入children的屬性,並把child.vue, child2.vue, child3.vue的路徑相關設定塞進去

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
export default new VueRouter({
routes:[
{
name:'首頁',
path:'/index',
component:Home
},
{
name:'分頁',
path:'/page',
component:Page,
children:[ // 插入巢狀路由內容
{
name:'child1',
path:'',
component:child_1
},
{
name:'child2',
path:'child2',
component:child_2
},
{
name:'child3',
path:'child3',
component:child_3
}
]
}
]
});

你可以看到,我們對Page又加了一個children屬性,並在裡面加了要引入的元件。
而你可以特別注意到,我們沒有對child1的path設值,這是因為,我們把它當為Page內容的預設值,也就是說Page元件<router-view>裡面的內容,預設會是card1的內容。

step4.
製作切換card1, card2, card3的內容
首先,我們就到pages.vue檔案中,加入<router-link></router-link>的元件,並透過to的方式來切換它們之間的內容。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<template>
<div>
<router-link to="/page">卡片一</router-link>
<router-link to="/page/child2">卡片二</router-link>
<router-link to="/page/child3">卡片三</router-link>
<div class="card" style="width: 18rem;">
<router-view></router-view>
</div>
</div>
</template>

<script>
export default {
name: 'HelloWorld',
data () {
return{

}
}
}
</script>

你可以看到,我們新增了三個router-link,並在這些標籤裡面,加入了to屬性,也就是它要跑去哪個頁面的路徑。

注意,元件檔絕對路徑的引用

你看上面router-link是直接用/page/child2 ,是用絕對路徑來引用元件檔。
不要用相對路徑來引入元件,即page/child2,這樣容易造成路徑檔案引用錯誤,要特別小心。

使用動態路由切換頁面 Ajax 結果

這個動態路由的功用就在於
透過動態路由來載入不同的內容,並將這些內容加到固定的版型中。

加入動態路由

首先,我們先到index.js檔案中,對card3的元件內容的path屬性做調整

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
export default new VueRouter({
routes:[
{
name:'首頁',
path:'/index',
component:Home
},
{
name:'分頁',
path:'/page',
component:Page,
children:[
{
name:'child1',
path:'',
component:child_1
},
{
name:'child2',
path:'child2',
component:child_2
},
{
name:'child3',
path:'child/:id', // 動態路由
component:child_3
}
]
}
]
});

接著,你去按頁面上卡片三的按鈕,此時,頁面應該是會失效的。
那你就把原本的卡片三路徑
http://localhost:8080/#/page/child3
改成
http://localhost:8080/#/page/child/ffff

這個時候,頁面應該就會呈現 child3 的內容囉。

取得動態路由內容

step1.
我們先取得我們剛剛修改的動態路由的id
你先去child3.vue的元件檔中,新增created的hook,並透過log來看看它的id是什麼

1
2
3
4
5
6
7
8
9
10
11
12
13
<script>
export default {
name: 'HelloWorld',
data () {
return{

}
},
created:function(){
console.log(this.$route.params.id); // 取得它的id內容
}
}
</script>

透過以上的語法,我們可以在 child3.vue 元件創建的時候,取得該元件路由中的 id 屬性值。

搭配vue.axios的功能

那為什麼要取得這個router的id呢,因為,要把它跟axios一起使用。
以下內容為 child3.vue 加入 axios 來取得 api 的內容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
---child3.vue元件檔---
<script>
export default {
name: 'HelloWorld',
data () {
return{

}
},
created:function(){
console.log(this.$route.params.id);
this.$http.get('https://randomuser.me/api/').then((response) => {
console.log(response)
})
}
}
</script>

如此,就能取得api的結果。

那在這個random產出api的網址中,有一個seeds的功能,它可以產出固定api的內容。
那我們就可以藉由動態路由的方式,來存取同一份資料囉。
修改一下 child3.vue 的內容。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
---child3.vue元件檔---
<script>
export default {
name: 'HelloWorld',
data () {
return{

}
},
created:function(){
var id = this.$route.params.id;
this.$http.get(`https://randomuser.me/api/?seed=${id}`).then((response) => {
console.log(response)
})
}
}
</script>

你用以上的寫法,就可以藉由console.log中的data裡面的內容,在每一次頁面刷新的時候,
都是相同的喔。
data的內容

命名路由,同一個路徑載入兩個頁面元件

假設在同一個畫面下,要執行兩個router-view

在App.vue檔案中,
我們在新增的.container的裡面跟外面分別加入<router-view></router-view>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<template>
<div id="app">
<nav class="navbar navbar-expand-sm navbar-light bg-light">
<div class="container-fluid">
<a class="navbar-brand" href="#">Navbar</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
<li class="nav-item">
<router-link class="nav-link active" :to="{name:'首頁'}">Home</router-link>
</li>
<li class="nav-item">
<router-link class="nav-link" to="/Page">Page</router-link>
</li>
</ul>
</div>
</div>
</nav>

<router-view name="menu"></router-view> // 新增 router-view
<div class="container">
<router-view></router-view> // 新增 router-view
</div>
</div>
</template>

你可以看到在.container裡面有一個router-view,它是吃預設的樣式。
外層也有一個router-view,我們特別為它的name屬性命名為menu。

step2.
接著,我們在page.vue的同一層目錄中,新增另一個menu.vue的元件檔。
並且,我們將原本寫在App.vue的router-link內容,都移到menu.vue元件檔中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
---menu.vue元件檔---
<template>
<div>
<nav aria-label="breadcrumb">
<ol class="breadcrumb">
<li class="breadcrumb-item">
<router-link to="/page">卡片一</router-link>
</li>
<li class="breadcrumb-item">
<router-link to="/page/child2">卡片二</router-link>
</li>
<li class="breadcrumb-item active" aria-current="page">
<router-link to="/page/child3">卡片三</router-link>
</li>
</ol>
</nav>
</div>
</template>

<script>
export default {
name: 'menu',
data () {
return{

}
}
}
</script>

你可以看到,我們把那些router-link從page.vue檔案中,抓來menu.vue檔。
所以,此時,page.vue元件檔,只會剩下.card的部分。

step3.
接著,我們到index.js檔案中,去匯入剛剛新增的menu.vue元件檔
並在routes使用components,來同時匯入Page和menu這兩個元件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
import Vue from 'vue';
import VueRouter from 'vue-router';

import Home from '@/components/HelloWorld'
import Page from '@/components/pages/pages'
import child_1 from '@/components/pages/child'
import child_2 from '@/components/pages/child2'
import child_3 from '@/components/pages/child3'
import Menu from '@/components/pages/menu' // 匯入Menu元件

Vue.use(VueRouter);

export default new VueRouter({
routes:[
{
name:'首頁',
path:'/index',
component:Home
},
{
name:'分頁',
path:'/page',
//component:Page, // 原本只有引用 Page 元件
components:{
default: Page,
menu: Menu, // 加入 Menu 元件
},
children:[
{
name:'child1',
path:'',
component:child_1
},
{
name:'child2',
path:'child2',
component:child_2
},
{
name:'child3',
path:'child3',
component:child_3
}
]
}
]
});

你可以看到components屬性是一個物件,然後它裡面有兩個屬性
default的值是Page,也就是Page元件,
而menu的值是Menu,也就是我們剛剛製作的Menu元件囉,
那要注意一下,這個menu的屬性名稱,要跟你在App.vue元件中,
你為那個在.container外層的router-view所加入的name屬性的值menu一樣喔。

經過以上的步驟,你應該就可以成功地在Page頁面上,同時呈現兩個不同的router-view元件囉。

修正小錯誤

以上的範例你可以知道,page元件的內容預設是吃到child1的內容,
但是,瀏覽器上會跳以下這個錯誤
瀏覽器小錯誤

它是說 page 分頁中,已經有預設的元件了,就是 child1 元件,會造成 child1 元件的內容不會被渲染出來。
所以,要移除 page 元件的name 的屬性內容。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
---router資料夾中的index.js檔案---
export default new VueRouter({
routes:[
{
name:'首頁',
path:'/index',
component:Home
},
{
//name:'分頁', // 元件呈現名稱 -- 註解掉
path:'/page',
//component:Page , // 它所對應的原件
components:{
default: Page,
menu: Menu,
},
children:[
{
name:'child1',
path:'',
component:child_1
},
{
name:'child2',
path:'child2',
component:child_2
},
{
name:'child3',
path:'child3',
component:child_3
}
]
}
]
});

你看,我們將 page 元件檔的 name:’分頁’的部分註解掉,之後,上面那個錯誤就不會再出現囉~~