---
# System prepended metadata

title: Vue Router
tags: [Vue]

---

###### tags: `Vue`

# Vue Router

# 0. 大綱

Vue 與以前寫的 jquery 的架構大相逕庭，jquery 所建立出來的網頁屬於多頁式網頁(MPA)，而Vue所建立出來的網頁為單頁式網頁(SPA)，簡單說就是進入其他網頁而網址會變動但並無跳轉的跡象，~~讓使用者產生出網頁很流暢的錯覺~~。要如何達成這個魔法，就是使用到本篇所提到的Vue-Router。

# 1. 安裝

## 1.1. 在建立專案安裝

### 1.1.1 透過Vue UI建立專案時

![](https://i.imgur.com/18kpoF6.png)


![](https://i.imgur.com/5eGgHnt.png)


1. 在建立專案，選擇專案模板時，選擇”手動”，按下一步。
2. 選取Router選項即可。
3. 建立成功，即可在該專案的/src找到系統自動建立的/router/index.js。
    
    ![](https://i.imgur.com/N0QGTHl.png)


### 1.1.2 透過指令建立專案時

![](https://i.imgur.com/7IwqrDe.png)


![](https://i.imgur.com/1OrZ7Ya.png)


1. 輸入指令建立專案後，選擇第3個選項。
2. 選擇選項”Router”。
3. 之後的部分就依個人需求自訂，
4. 建立成功，即可在該專案的/src找到系統自動建立的/router/index.js。

## 1.2. 在專案建立後加裝

### 1.2.1 透過Vue UI加入

![](https://i.imgur.com/tp5Eyjx.png)


1. 按下最左邊的第2個”插件”。
2. 找到右上角的按鈕”新增vue-router”並按下，並按下"繼續"
3. 待安裝完，即可在該專案的/src找到系統自動建立的/router/index.js。

### 1.2.2 透過指令加裝

![](https://i.imgur.com/vFMAQDl.png)


1. 進入該專案，輸入指令:
    
    >💡 `npm install vue-router -save`

    
2. 在該專案下的/src中建立一個新資料夾，命名為”router”，並在其中建立”index.js”。
    
    ![](https://i.imgur.com/qOTyPJk.png)

    
3. 編輯/router/index.js，內容為:
    
    ```jsx
    import { createRouter, createWebHashHistory } from 'vue-router'
    
    import Home from '../components/HelloWorld.vue'
    const About = { template: '<div>About</div>'}
    
    const routes = [
      {
        path: '/',
        name: 'home',
        component: Home
      },
      {
        path: '/about',
        name: 'about',
        component: About
      }
    ]
    
    const router = createRouter({
      history: createWebHashHistory(),
      routes
    })
    
    export default router
    ```
    
4. 編輯最外層的main.js，將router加入。
    
    ```jsx
    import { createApp } from 'vue'
    import App from './App.vue'
    import router from './router'; //新增這行
    
    //createApp(App).mount('#app')   //將這行註解或刪除
    
    const app = createApp(App); //新增這行
    
    app.use(router) //新增這行，將router引進
    
    app.mount('#app') //新增這行
    ```
    
5. 編輯app.vue:
    
    ```html
    <template>
      <router-link to="/">Home</router-link> <!--新增這行-->
      <router-link to="/about">About</router-link> <!--新增這行-->
      <router-view></router-view> <!--新增這行-->
    
      <!--<img alt="Vue logo" src="./assets/logo.png">    刪除或註解這行-->
      <!--<HelloWorld msg="Welcome to Your Vue.js App"/>  刪除或註解這行-->
    </template>
    
    <script>
    import HelloWorld from './components/HelloWorld.vue' //刪除或註解這行
    
    export default {
      name: 'App',
      components: {
        HelloWorld //刪除或註解這行
      }
    }
    </script>
    
    <style>
    #app {
      font-family: Avenir, Helvetica, Arial, sans-serif;
      -webkit-font-smoothing: antialiased;
      -moz-osx-font-smoothing: grayscale;
      text-align: center;
      color: #2c3e50;
      margin-top: 60px;
    }
    </style>
    ```
    
6. 啟動後，看到此畫面即成功。
    
    ![](https://i.imgur.com/ek2mTCW.png)

    

# 2. 介紹功能

## 2.1 建立Router

```jsx
const router = createRouter({
  history: createWebHashHistory(),
  routes
})
```

- 使用`createRouter(options)`來建立Router
- 主要常用的options有:
    - history :
        - `createWebHashHistory()`
        - `createWebHistory()`
    - routes : Router的初始路由列表，細節留至下一小節詳細說明。

## 2.2 routes

- routes為初始的路由列表，之後若要再新增其他路由可有其他指令(ex: `addRoute`)辦到。

```jsx
const routes = [
  {
    path: '/',
    name: 'home',
    component: Home
  },
  {
    path: '/about',
    name: 'about',
    component: About
  }
]
```

- 通常會有很多路由，所以會獨立提出來寫，而非直接寫在`createRouter`裡
- 每個route中常用的有:
    - **path**: 進入該頁面的路徑。
        - 例如: `path: ‘about’`，網頁網址為`http://localhost:12345`，則要進入此頁面則須輸入`http://localhost:12345/about`
    - **name**: 該路由的名稱。
    - **component**: 該路由的元件。
        - 例如: 上面的Home的元件取自`import Home from '../components/HelloWorld.vue’`，則當進入home頁面時，`HelloWorld.vue`就會載入至`<router-view></router-view>`
        - 除了先將元件載入再指派給route，也可等進入該頁面在加載該元件的方法。
            - 例如: `component: ()⇒import('../components/HelloWorld.vue’)`。
    - **meta**: 自定義的參數
        - 例如: 該頁面的title，index等，並使用route.meta.title等來讀取。
    - ****redirect: 進入該頁面時，重定向到指定的頁面。****
    - **alias**: 路由的別名。
        - 例如: `path: ‘/’,alias: ‘/home’`，則使用/或/home都匯到同意頁面。
    - **beforeEnter**: 進入該路由之前做某些事，待下一節說明。

# 3. 導航守衛(****Navigation Guards****)

- 分為
    - beforeEach
    - beforeResolve
    - afterEach
    - beforeEnter
    - beforeRouteEnter、beforeRouteUpdate、beforeRouteLeave

## 3.1 全域守衛

### 3.1.1 beforeEach

- 使用`router.beforeEach`來使用此守衛。
    
    ```jsx
    const router = createRouter({ ... })
    
    router.beforeEach((to, from) => {
    	if(...){
    		return {name: "/"}
    	}else if(...){
    		return '/'
    	}else{
    		// ...
    	  // 返回 false 以取消導航
    	  return false
    	}
    })
    ```
    
    - 此守衛將在進入路由之前執行，但此時路由尚未解析，所以不可調用meta屬性。
    - to: 即將進入的路由
    - from: 即將離開的路由
    - 如果return false，則取消路由，true或undefine則為成功

### 3.1.2 beforeResolve

```jsx
const router = createRouter({ ... })

router.beforeResolve((to, from) => {
  
})
```

- 此守衛與beforeEach類似，但beforeResolve是在路由解析完後才被調用的，所以可以使用meta屬性。

### 3.1.3 afterEach

```jsx
router.afterEach((to, from) => {
  sendToAnalytics(to.fullPath)
})
```

- 此守衛在導航成功後，頁面渲染前，被調用。
- 不能改變導航路徑

## 3.2 路由內的守衛

### 3.2.1 beforeEnter

```jsx
const routes = [
  {
    path: '/abc',
    component: Test,
    beforeEnter: (to, from) => {
    },
  },
]
```

- beforeEnter在進入該路由時被調用。
- 可使用函數傳遞:

```jsx
function removeQueryParams(to) {
  if (Object.keys(to.query).length)
    return { path: to.path, query: {}, hash: to.hash }
}

function removeHash(to) {
  if (to.hash) return { path: to.path, query: to.query, hash: '' }
}

const routes = [
  {
    path: '/users/:id',
    component: UserDetails,
    beforeEnter: [removeQueryParams, removeHash],
  },
  {
    path: '/about',
    component: UserDetails,
    beforeEnter: [removeQueryParams],
  },
]
```

## 3.3 完整的導航流程

1. 導航被觸發。
2. 在要離開的元件裡調用守衛`beforeRouteLeave`。
3. 調用全域守衛`beforeEach`。
4. 在重用的元件裡調用守衛`beforeRouteUpdate`。
5. 在路由配置裡調用`beforeEnter`。
6. 解析異步路由元件。
7. 在被啟動的元件裡調用`beforeRouteEnter`。
8. 調用全域的守衛`beforeResolve`。
9. 導航被確認。
10. 調用全域的鉤子`afterEach`。
11. 觸發 DOM 更新。
12. 調用守衛中傳給的回調函數，創建好的元件實例會作為回調函數的參數傳入。`beforeRouteEnternext`

# 4. 參考資料

[4-4 路由守衛（Navigation Guards） | 重新認識 Vue.js | Kuro Hsu](https://book.vue.tw/CH4/4-4-navigation-guards.html)

[Navigation Guards | Vue Router](https://router.vuejs.org/guide/advanced/navigation-guards.html)