>[success] # 路由匹配規則
[官方文檔](https://router.vuejs.org/zh/guide/essentials/route-matching-syntax.html#%E5%9C%A8%E5%8F%82%E6%95%B0%E4%B8%AD%E8%87%AA%E5%AE%9A%E4%B9%89%E6%AD%A3%E5%88%99)對路由匹配做了詳細說明,其中路由匹配支持正則表達式,對其中幾個官方說到做了一個簡單概述提取,具體更多可以參考官方文檔
>[info] ## 動態路由
1. 動態路由 可以適應`RESTful `這種路由風格,當路由是:`/user/foo` 和 `/user/bar` 的形式的時候可以利用一個**路徑參數使用冒號 : 標記**
>[danger] ##### 官方給出一個動態參數表格
1. 動態路由參數可以通過 `$route.params` 進行獲取
| 模式 | 匹配路徑 | $route.params |
| --- | --- | --- |
| /user/:username | /user/evan | `{ username: 'evan' }` |
| /user/:username/post/:post\_id | /user/evan/post/123 | `{ username: 'evan', post_id: '123' }` |
>[danger] ##### 路由響應
1. `/users/johnny`導航到`/users/jolyne`時,**相同的組件實例將被重復使用**。因為兩個路由都渲染同個組件,比起銷毀再創建,復用則顯得更加高效。**不過,這也意味著組件的生命周期鉤子不會被調用**,因此不會觸發從`beforeCreate`到`mounted`這個區間的生命周期
2. 產生問題一般情況下在一些初始化操作例如 接口請求的時候一般會在`beforeCreate`到`mounted`區間的生命周期來請求接口不會在觸發這些生命周期相對的替代辦法
* 使用`watch`去監聽重新觸發,第一次不會觸發想觸發使用 `immediate `立即執行
* 用`beforeRouteUpdate`導航守衛,第一次不會觸發
* 使用 `watchEffect`去監聽重新觸發,第一次會觸發

注:**useRoute** 函數返回的是一個`Reactive ` 對象
* 路由部分的格式
~~~
{
path: "/about/:id",
name: "about",
component: () =>
import(/* webpackChunkName: "about" */ "../views/AboutView.vue"),
},
~~~
~~~html
<template>
<div class="about">
<h1>This is an about page</h1>
</div>
</template>
<script setup>
import { watch, watchEffect, isReactive } from "vue";
import { useRoute, onBeforeRouteUpdate } from "vue-router";
const route = useRoute();
console.log(isReactive(route)); // true
// 監聽動態路由變化,第一次初始化頁面時候不會觸發,除非開啟深監聽
watch(
() => route.params.id,
(newVal, oldVal) => {
console.log(newVal, oldVal);
}
);
// 那次都可以觸發
watchEffect(() => {
console.log(route.params.id);
});
// 利用路由守衛,第一次初始化頁面時候不會觸發
onBeforeRouteUpdate((to, from) => {
console.log(to.params.id);
console.log(from.params.id);
});
</script>
~~~
>[info] ## 匹配規則
1. 動態路由這類匹配可能是復雜的,因此可以使用一些規則進行更為復雜的路由映射
2. 格式為**路徑參數使用冒號 : 標記(正則)**,` { path: '/:orderId(\\d+)' }`
3. 將匹配以 `/user-` 開頭的所有內容,并將其放在 `$route.params.afterUser` 下 `{ path: '/user-:afterUser(.*)', component: UserGeneric },` `afterUser(.*)` 作為匹配參數接收部分
>[danger] ##### 匹配格式
1. **默認情況下,所有路由是不區分大小寫的,并且能匹配帶有或不帶有尾部斜線的路由**,路由`/users`將匹配`/users`、`/users/`、甚至`/Users/`
2. 通過`strict`和`sensitive`選項來修改,它們可以既可以應用在整個全局路由上,又可以應用于當前路由上
* **strict**,類型: boolean (可選),嚴格檢查路徑末尾是否有尾部斜線(`/`)。默認為`false`,意味著默認情況下,路由`/users`同時匹配`/users`和`/users/`。注意這也可以在路由級別上設置
* **sensitive** 類型: boolean (可選),使路由匹配區分大小寫,默認為`false`。注意這也可以在路由級別上設置
~~~
const router = createRouter({
history: createWebHistory(),
routes: [
// 將匹配 /users/posva 而非:
// - /users/posva/ 當 strict: true
// - /Users/posva 當 sensitive: true
{ path: '/users/:id', sensitive: true },
// 將匹配 /users, /Users, 以及 /users/42 而非 /users/ 或 /users/42/
{ path: '/users/:id?' },
]
strict: true, // applies to all routes
})
~~~
>[danger] ##### 僅匹配數字
~~~
const routes = [
// /:orderId -> 僅匹配數字
{ path: '/:orderId(\\d+)' },
// /:productName -> 匹配其他任何內容
{ path: '/:productName' },
]
~~~
動態路由是由使用`:` 做動態路由參數接受,此時并沒有限制接受參數類型,但如果此時僅僅想是數字或者字符串這種指定參數類型時候就可以使用正則,上面的例子如果用戶輸入的網址是`http://localhost:8080/ppp` 此時并不會進入` { path: '/:orderId(\\d+)' }` 所映射的路由組件,而是會映射到` { path: '/:productName' }` 所對應的組件上,相對來說如果想映射到` { path: '/:orderId(\\d+)' }` 所對應的組件此時地址需要是`http://localhost:8080/456789`
* **案例說明**
要注意 `/about/:productName` `/about/:orderId(\\d+)` 這樣設置路由是不可以的,和根目錄直接設置不同,上面這種同一前綴并不會具體區分,相反誰在下面誰權重高
~~~
{
path: "/o/:productName",
component: () =>
import(/* webpackChunkName: "about" */ "../views/AboutView.vue"),
},
{
path: "/p/:orderId(\\d+)",
component: () =>
import(/* webpackChunkName: "about" */ "../views/AboutView.vue"),
},
~~~
~~~html
<template>
<div class="about">
<h1>This is an about page</h1>
</div>
</template>
<script setup>
import { watchEffect, isReactive } from "vue";
import { useRoute } from "vue-router";
const route = useRoute();
console.log(isReactive(route));
// 那次都可以觸發
watchEffect(() => {
console.log(route.params.orderId); // http://localhost:8080/p/133
console.log(route.params.productName); // http://localhost:8080/o/1ww
});
</script>
~~~
>[danger] ##### ? 可選參數
~~~
const routes = [
// 匹配 /users 和 /users/posva
{ path: '/users/:userId?' },
// 匹配 /users 和 /users/42
{ path: '/users/:userId(\\d+)?' },
]
~~~
>[danger] ##### 可重復參數
正則可使用`*` 和 `+` 做參數匹配,同樣支持正則的`vue-router` 也可以使用`*` 和 `+` 做參數匹配個數校驗
~~~
const routes = [
// /:chapters -> 匹配 /one, /one/two, /one/two/three, 等
{ path: '/:chapters+' },
// /:chapters -> 匹配 /, /one, /one/two, /one/two/three, 等
{ path: '/:chapters*' },
]
~~~
或者配合正則
~~~
const routes = [
// 僅匹配數字
// 匹配 /1, /1/2, 等
{ path: '/:chapters(\\d+)+' },
// 匹配 /, /1, /1/2, 等
{ path: '/:chapters(\\d+)*' },
]
~~~
>[danger] ##### 返回路由地址
1. 下面案例打開一個新的窗口 兩種方式
* 案例
~~~
{
path: "/about/:productName",
name: "about",
component: () =>
import(/* webpackChunkName: "about" */ "../views/AboutView.vue"),
},
~~~
~~~
<template>
<div class="about">
<h1 @click="open">This is an about page</h1>
</div>
</template>
<script setup>
import { watchEffect, isReactive } from "vue";
import { useRoute, useRouter } from "vue-router";
const route = useRoute();
const router = useRouter();
console.log(isReactive(route));
// 那次都可以觸發
watchEffect(() => {
console.log(route.params.productName);
});
function open() {
var { href } = router.resolve({
name: "about",
params: { productName: 123 },
});
window.open(href, "_blank"); // 方式1
// window.open("./123", "_blank"); // 方式2
}
</script>
~~~
>[info] ## 測試路徑工具
[路徑排名工具](https://paths.esm.dev/?p=AAMeJSyAwR4UbFDAFxAcAGAIJXMAAA..#)
>[info] ## 官網
[# 路由的匹配語法](https://router.vuejs.org/zh/guide/essentials/route-matching-syntax.html)
- 官網給的工具
- 聲明vue2 和 vue3
- 指令速覽
- Mustache -- 語法
- v-once -- 只渲染一次
- v-text -- 插入文本
- v-html -- 渲染html
- v-pre -- 顯示原始的Mustache標簽
- v-cloak -- 遮蓋
- v-memo(新)-- 緩存指定值
- v-if/v-show -- 條件渲染
- v-for -- 循環
- v-bind -- 知識
- v-bind -- 修飾符
- v-on -- 點擊事件
- v-model -- 雙向綁定
- 其他基礎知識速覽
- 快速使用
- 常識知識點
- key -- 作用 (后續要更新)
- computed -- 計算屬性
- watch -- 偵聽
- 防抖和節流
- vue3 -- 生命周期
- vue-cli 和 vite 項目搭建方法
- vite -- 導入動態圖片
- 組件
- 單文件組件 -- SFC
- 組件通信 -- porp
- 組件通信 -- $emit
- 組件通信 -- Provide / Inject
- 組件通信 -- 全局事件總線mitt庫
- 插槽 -- slot
- 整體使用案例
- 動態組件 -- is
- keep-alive
- 分包 -- 異步組價
- mixin -- 混入
- v-model-- 組件
- 使用計算屬性
- v-model -- 自定義修飾符
- Suspense -- 實驗屬性
- Teleport -- 指定掛載
- 組件實例 -- $ 屬性
- Option API VS Composition API
- Setup -- 組合API 入口
- api -- reactive
- api -- ref
- 使用ref 和 reactive 場景
- api -- toRefs 和 toRef
- api -- readonly
- 判斷性 -- API
- 功能性 -- API
- api -- computed
- api -- $ref 使用
- api -- 生命周期
- Provide 和 Inject
- watch
- watchEffect
- watch vs. watchEffect
- 簡單使用composition Api
- 響應性語法糖
- css -- 功能
- 修改css -- :deep() 和 var
- Vue3.2 -- 語法
- ts -- vscode 配置
- attrs/emit/props/expose/slots -- 使用
- props -- defineProps
- props -- defineProps Ts
- emit -- defineEmits
- emit -- defineEmits Ts
- $ref -- defineExpose
- slots/attrs -- useSlots() 和 useAttrs()
- 自定義指令
- Vue -- 插件
- Vue2.x 和 Vue3.x 不同點
- $children -- 移除
- v-for 和 ref
- attribute 強制行為
- 按鍵修飾符
- v-if 和 v-for 優先級
- 組件使用 v-model -- 非兼容
- 組件
- h -- 函數
- jsx -- 編寫
- Vue -- Router
- 了解路由和vue搭配
- vueRouter -- 簡單實現
- 安裝即使用
- 路由懶加載
- router-view
- router-link
- 路由匹配規則
- 404 頁面配置
- 路由嵌套
- 路由組件傳參
- 路由重定向和別名
- 路由跳轉方法
- 命名路由
- 命名視圖
- Composition API
- 路由守衛
- 路由元信息
- 路由其他方法 -- 添加/刪除/獲取
- 服務器配置映射
- 其他
- Vuex -- 狀態管理
- Option Api -- VUEX
- composition API -- VUEX
- module -- VUEX
- 刷新后vuex 數據同步
- 小技巧
- Pinia -- 狀態管理
- 開始使用
- pinia -- state
- pinia -- getter
- pinia -- action
- pinia -- 插件 ??
- Vue 源碼解讀
- 開發感悟
- 練手項目