---
# System prepended metadata

title: VUE 3 課程筆記 (八) Vue Router
tags: [VUE 3 課程筆記]

---

---
tags: VUE 3 課程筆記
---

# VUE 3 課程筆記 (八) Vue Router
## what is Vue Router
### 後端路由 router 主要是在做任務分配的工作：
![](https://i.imgur.com/Zvjt32D.png)
Client 跟 Server 要資料然後由 router 分配再讓 controller 告訴 model 需要什麼資料，再把資料跟 view 結合後回傳給 server 再提供給 Client
### 前端路由：
由前端所模擬的路由所以網址中間會多一個 /#/
會建立一個虛擬的路徑，然後依照路徑上的需求調用要用到的元件

### Vue Router 開發流程：
1. 引入 Vue Router 環境
2. 定義元件
3. 定義路由表
4. 加入對應連結

## Vue CLI + Vue Router
路由表會放在 ```router/index.js``` 這隻檔案裡面
1. 引入 Vue Router 環境(基本上 Vue CLI 已經會把所有基本設定都建立好了)
```javascript=
import { createRouter, createWebHashHistory } from 'vue-router'
```
這邊就是路由表的設定區域，設定內容會有 path 、 name 、 component 三個部分， path 是設定路徑， name 是頁面名稱（方便動態載入）， component 則是 import 頁面檔案的路徑
```javascript=
const routes = [
  {
    path: '/',
    name: 'home',
    component: () => import('../views/HomeView.vue')
  },
  {
    path: '/about',
    name: 'about',
    // route level code-splitting
    // this generates a separate chunk (about.[hash].js) for this route
    // which is lazy-loaded when the route is visited.
    component: () => import(/* webpackChunkName: "about" */ '../views/AboutView.vue')
  },
  {
    path: '/newpage',
    name: '新增頁面',
    component: () => import('../views/NewPage.vue')
  }
]
```
這邊是基本預設，history 的部分是讓這個 Vue Router 是用一個 Hash 的方式（/#/），下面那個 routes 就是對應上面路由表的內容
最後再 export 這個檔案給 main.js 去 import
```javascript=
const router = createRouter({
  history: createWebHashHistory(),
  routes
})

export default router
```
3. 定義元件
這邊會先把頁面 ＆ 元件都先準備好檔案（不一定要先都寫完，有檔案就好）
5. 定義路由表
開始填寫 ```index.js``` 裡面 routes 區域的 path、name、component
7. 加入對應連結
在 ```App.vue```這個基礎頁面的檔案當中加入我們所需要加入的 ```<router-link to="path"></router-link>```以及顯示 頁面/元件 的```<router-view></router-view>```

## 巢狀路由
巢狀路由就是在原本的路由表的頁面裡面再加入下一層的路由，新增方法跟第一層路由大同小異
```javascript=
const routes = [
  {
    // 頁面一
    path: '/',
    name: 'home',
    component: () => import('../檔案路徑'),
    // 新增一個 children 陣列來放置下一層的路由
    children: [
        {
            path: 'pathName',
            component: () => import('../檔案路徑')
        }
    ]
  },
  {
    // 頁面二
  },
  {
    // 頁面三
  }
]
```
完成後一樣在頁面裏面加入```<router-link to="page/path"></router-link>```以及```<router-view></router-view>```
這邊要注意，```<router-link to="">```的路徑要寫完整，是包含兩層（/page/子page）的哦
## 一個元件插入多個視圖-具名視圖
可以在同一個元件裏面插入多個 router-view 然後可以增加 name 屬性
```htmlembedded=
<router-view name="name1"></router-view>
<router-view name="name2"></router-view>
```
載入路由表的時候會改變一個地方：
```javascript=
{
    path:'元件路由路徑',
    component: () => import('元件檔案路徑'),
    children: [
        {
            path:'元件路由路徑',
            components: {
                name1: () => import('元件檔案路徑'),
                name2: () => import('元件檔案路徑')
            }
        },
        {
            path:'元件路由路徑',
            components: {
                name3: () => import('元件檔案路徑'),
                name4: () => import('元件檔案路徑')
            }
        }
    ]
}
```
這邊 components 裡面的物件屬性名稱會使用 router-view 上面的屬性名稱做對應。
最後再把對應連結 ```router-link```加上去，完成！
## 透過參數決定路由內容-動態路由
因為產品或相關資料會有超多，把資料一個一個建立到路由表上面根本就是神經病工作，所以可以使用動態路由，運用 axios + router 去判斷要接收的資訊是哪個產品，直接動態建立路由表。
### 關鍵點：把路由表變成動態的
```javascript=
{
  path:'元件路由路徑/:id',
  component:() => import('元件檔案路徑')
}
```
這邊 :id 是一個動態對應要顯示資料的 id 的東西， 約莫就是一個在 router 裡面的 ":"(v-bind) !?
### 元件裏面抓 id （這邊用一個 randomuser 做示範）
```javascript=
import axios from 'axios';

export default {
    created () {
        // 把 id 抓出來
        const seed = this.$route.params.id;
        // 這邊會因為每個 api 放 id 的位置不同
        // 在 this.$route 後面要接的位置會不同
        // 要記得看一下 id 在資料哪裡哦～
        axios.get(`遠端api網址/?seed=${seed}`)
        .then(
            (res) => {
                要存資料的動作
            }
        )
    }
}
```
## 動態路由搭配 Props
運用 props 直接從路由裡面撈 id 
路由表裡面的東西會長成這樣
```javascript=
{
    path: '元件路由路徑/:id',
    component: () => import('元件檔案路徑'),
    props: (route) => {
        return {
            // 在這邊觸發 route 再用 props 結合到元件上
            id: route.params.id,
        }
    }
}

```
```htmlembedded=
<script>
    import axios from 'axios';

    export default {
        // 加上 props 的 功能帶上 id
        props: ['id'],
        created() {
            const seed = this.id
            axios.get(`遠端 api 網址/?seed=${seed}`)
            .then(
              (res) => {
                  console.log(res)
              }
            )
        },
    }
</script>
```
## 路由方法介紹
$route 是可以取得路由的屬性
$router 是可以使用 router 的方法
下面有幾種好像比較常會用到的路由方法：
```javascript=
eport default {
  methods: {
      getRoute () {
          // 可以看到所有的 $router 方法
          console.log(this.$router)
      },
      // 包含歷史紀錄
      push () {
          // 方法一
          this.$router.push('加入路由路徑')
          // 方法二
          this.$router.push({
              name: 'router-link 的 name'
          })
      },
      // 不會產生歷史紀錄
      replace () {
          // 方法一
          this.$router.replace('加入路由路徑')
          // 方法二
          this.$router.replace({
              name: 'router-link 的 name'
          })
      },
      // 前進到歷史紀錄的前或後幾頁
      go () {
          this.$router.go(+/- 頁數)
      }
      
  }
}
```
## 預設路徑以及重新導向
在網址有錯誤的時候 vue 會直接跳一個全白的頁面然後在 console 裡面顯示錯誤給你看，不過這樣對使用者來講真的有點莫名其妙，所以我們可以用兩種方法來提升使用者的體驗，不會那麼不知所措

### 做一個路徑錯誤的 404 頁面
```javascript=
{
    // 這邊就是用 ＊ 去選擇所有頁面比對有沒有符合的路徑
    // 如果沒有就會導到這個 router-link 來
    path: '/:pathMatch(.*)*',
    component: () => import('404 頁面的檔案路徑')
},
```
這樣就會顯示我們所設定的 404 頁面給使用者知道網址有錯誤哦

### 重新導向
```javascript
{
    path: '/元件路由路徑/：pathMatch(.*)*',
        redirect: {
            // 重新導向到的位置
            // 可以用路徑也可以使用設定好的 name
            name: 'Home',
        }
}
```
這樣網址有錯誤的時候就會直接被導回首頁囉
### 補充一下比對路徑的正規表達式的意思：
```javascript!
. 代表任意字元

* 代表 0 個或多個以上

.* 就變成任意字元 0 個或多個以上
```
另外，也可以習慣的將 404 頁面放到路由表的最後一個，這樣會比較知道自己要去哪裡找東西，另外，這樣的思考方式也很像後端開發路由的想法（有一致性，因為後端的路由確實是從上到下比對）
## 路由設定選項
這個會寫在 createRouter 裏面，有幾個不錯用的設定可以參考一下：
```javascript=
const router = createRouter({
    // history & routes 是 vue router 起始就有的
    histoiry: createWebHashHistory(),
    routes,
    // 為 router-link 增加啟用
    linkActiveClass: 'class 名稱，bootstrap 會使用 active',
    // to 是前往的頁面 
    // from 是從哪個頁面出發 
    // savePosition 是我前往頁面時，頁面的高度位置
    scrollBehavior(to, from, savePosition) {
        if (to.fullPath.match('頁面名稱')) {
            return {
                // 下一個頁面渲染好的時候的高度
                top: 0,
            }
        }
    },
    scrollBehavior(to, from, savePosition) {
        //也可以直接設定好高度就好，
        //這樣無論切過來前高度在哪裡，
        //到新頁面都會到下面 top 設定的高度
        return{
            top: 0,
        }
    }
})
```