>[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`去监听重新触发,第一次会触发
![](https://img.kancloud.cn/58/75/58758a6436605c40671fa2b6e45eaa60_1296x370.png)
注:**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 源码解读
- 开发感悟
- 练手项目