🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
>[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)