Vue3 - Router 路由參數與404頁面
tags: Vue
category: Front-End
description: Vue3 - Router 路由參數與404頁面
created_at: 2022/07/24 23:00:00
回到 手把手開始寫 Vue3
前言
有些框架所使用的路由可能預設就是使用正規表達式(Regexp
)去做匹配的,但在這邊他的路由預設是以字串做匹配的,而如果需要使用正規表達式,就需要使用待會第一個提到的東西,路由參數。
路由參數
有時候可能需要動態的匹配一些網址,例如 /users/1
跟 /users/2
渲染的都是同樣的一個組件,但是我要收到不同的資料而去渲染不同的東西,而那個數字 1
或 2
就是路由參數。
在定義之前,一樣先建立一個 Component
,好讓之後路由使用:
UserView.vue
<template>
<h1>This is an user page</h1>
</template>
再來加上路由:
{
path: "/users/:id",
component: () => import("../views/UserView.vue"),
},
而這邊 :
開頭的東西就是路由參數,名字可以自己取,像這邊取作 id
。
而使用方式可以從 route.params
當中拿到那個 id
,像下面:
<template>
<h1>This is an user page: {{ $route.params }}</h1>
</template>
這樣假設我去 /users/1
你會看到:
This is an user page: { "id": "1" }
那可能會想說,那如果我要在 script
當中寫,要怎麼拿到那個 $route
呢?
<script setup>
console.log($route);
</script>
因為上面這樣肯定會噴錯的。 ReferenceError: $route is not defined
這時就要使用 跟 React hook
很像的東西useRoute
了,去拿到 route
<script setup>
import { useRoute } from "vue-router";
const route = useRoute();
console.log(route.params);
</script>
這樣你就會看 Console
看到輸出 {id: '1'}
了。
這時候為了方便測試,修改一下 App.vue
的內容,也順便幫路由定義加上 name
屬性:
{
path: "/users/:id",
name: "users",
component: () => import("../views/UserView.vue"),
},
<script setup>
import { RouterLink, RouterView } from "vue-router";
</script>
<template>
<nav>
<RouterLink :to="{ name: 'users', params: { id: 1 } }">users 1</RouterLink>
<RouterLink :to="{ name: 'users', params: { id: 2 } }">users 2</RouterLink>
</nav>
<div>
<RouterView />
</div>
</template>
這時候就可以單純用點的去切換頁面了。
內容改了但 script
只跑一次?
對,因為他使用同一個 Component
,記得前幾篇應該有提到說如果能重複利用他就會盡量重複利用,所以他就沒有重新跑整個元件,所以當然你有生命周期也沒用,舉例來說:
onMounted(() => {
console.log(route.params);
});
就算你加了上面這段他還是只會跑一次,因為他就被掛上去一次啊!
解決方案參考
1. 監聽路由參數
import { watch } from "vue";
import { useRoute } from "vue-router";
const route = useRoute();
watch(
() => route.params,
(newParams, oldParams) => {
console.log("hi 我變了,", oldParams, newParams);
}
);
2. 使用路由守衛
你可以把他想成也是一種生命週期,不過他也可以取消你的轉址。
如果有寫過後端的人,其實就是路由的 Middleware
。
import { onBeforeRouteUpdate } from "vue-router";
onBeforeRouteUpdate((to, from) => {
console.log("hi 我變了,", from.params, to.params);
});
至於取消轉址行為,看範例
onBeforeRouteUpdate((to, from) => {
// 假設你做了一些判斷
return false;
});
這時你會發現你點連結之後他不理你,但其實他有進去那個函數,不相信自己 Console.log
看看。
3. 為 RouterView
加上 key
這時就要回到你的 App.vue
了
<RouterView :key="$route.path" />
前面幾篇也有提到說當 key
變了他就會認定是不同東西然後重新渲染,所以如果他的 key
是路由的 path
,那你每次轉址他就會重新渲染,那麼理所當然就會觸發生命週期了。
使用正規表達式
路由參數可以使用正規表達式去限制要匹配的東西,只要在路由參數後面加上括號再定義就可以。
貼幾個官方範例上來看看
const routes = [
// /:orderId -> 只接受數字
{ path: '/:orderId(\\d+)' },
// /:productName -> 任何東西都吃
{ path: '/:productName' },
]
const routes = [
// /:chapters -> 匹配一個或多個路由參數 /one, /one/two, /one/two/three, etc
{ path: '/:chapters+' },
// /:chapters -> 匹配零個或多個路由參數 /, /one, /one/two, /one/two/three, etc
{ path: '/:chapters*' },
]
// 假設 { path: '/:chapters*', name: 'chapters' },
router.resolve({ name: 'chapters', params: { chapters: [] } }).href
// 產出 /
router.resolve({ name: 'chapters', params: { chapters: ['a', 'b'] } }).href
// 產出 /a/b
// 假設 { path: '/:chapters+', name: 'chapters' },
router.resolve({ name: 'chapters', params: { chapters: [] } }).href
// 會噴錯,因為 `chapters` 不得為空
const routes = [
// 只接受數字
// 匹配 /1, /1/2, etc
{ path: '/:chapters(\\d+)+' },
// 匹配 /, /1, /1/2, etc
{ path: '/:chapters(\\d+)*' },
]
const routes = [
// 將匹配 /users 和 /users/posva
{ path: '/users/:userId?' },
// 將匹配 /users 和 /users/42
{ path: '/users/:userId(\\d+)?' },
]
基本上就是正規表達式的那幾套。
404頁面
當知道了上面使用正規表達式的方式之後,再看官方給的 404
範例,應該就不會太難懂
const routes = [
{ path: '/:pathMatch(.*)*', name: 'NotFound', component: NotFound },
]
也就是那個 :pathMatch
其實也可以改成你喜歡的東西 XD