切换导航
简历
工具
演示
查询
导航菜单
服务端
30
前端
114
数据库
82
进阶开发
8
桌面程序
2
QA
15
软件使用
36
规范协议
5
操作系统
11
AI
0
复用资源
6
硬件
0
标签
HTML
正则表达式
Json
包管理工具
vite
CSS
XPath
JavaScript
Jquery
less
ES6
Vue
React
vue 3
Layui
editor.md
sea.js
Zepto.js
mysql.js
mssql.js
NodeJs
Express
前端template
YAML
杂项
外部链接
.NET Core SDK和运行时安装包
淘宝 NPM 镜像
查询网
Tables Generator线上表格转换工具
引用cdn在线脚本和样式
首页
前端
Vue Router 路由参数与匹配规则
[TOC] ## 路由参数 在 Vue Router 中,可以在路径中使用一个动态字段来实现,称之为 路径参数 : ```js import User from './User.vue' // 这些都会传递给 `createRouter`,添加到router/index.js const routes = [ // 动态字段以冒号开始 { path: '/users/:id', component: User }, ] ``` 现在像 /users/johnny 和 /users/jolyne 这样的 URL 都会映射到同一个路由。 路径参数 用冒号 : 表示。当一个路由被匹配时,它的 params 的值将在每个组件中以 route.params 的形式暴露出来。因此,我们可以通过更新 User 的模板来呈现当前的用户 ID: ```HTML <template> <div> <!-- 当前路由可以通过 $route 在模板中访问 --> User {{ $route.params.id }} </div> </template> ``` ### 多参数路由 同一个路由中设置有多个 路径参数,它们会映射到 $route.params 上的相应字段。例如: |匹配模式|匹配路径|route.params| |--|--| |/users/:username|/users/eduardo|{ username: 'eduardo' }| |/users/:username/:postId|/users/eduardo/123|{ username: 'eduardo', postId: '123' }| |/users/:username/posts/:postId|/users/eduardo/posts/123|{ username: 'eduardo', postId: '123' }| ```js const routes = [ { path: '/users/:username', name: 'users', component: () => import('@study/RouterStudy.vue') }, { path: '/users/:username/:postId', name: 'users1', component: () => import('@study/RouterStudy.vue') }, { path: '/users/:username/posts/:postId', name: 'users2', component: () => import('@study/RouterStudy.vue') }, ] ``` ```HTML <template> <div> <RouterLink :to="{ name: 'users', params: { name: 'caoyl' } }">本页跳转</RouterLink> <RouterLink :to="{ name: 'users1', params: { name: 'caoyl2', age: 18 } }"> 本页跳转1 </RouterLink> <RouterLink :to="{ name: 'users2', params: { name: 'caoyl2', age: 30 } }"> 本页跳转2 </RouterLink> </div> </template> ``` ### 响应路由参数的变化 使用带有参数的路由时需要注意的是,当用户从 /users/johnny 导航到 /users/jolyne 时,相同的组件实例将被重复使用。因为两个路由都渲染同个组件,比起销毁再创建,复用则显得更加高效。不过,这也意味着`组件的生命周期钩子不会被调用。` 要对同一个组件中参数的变化做出响应的话,你可以简单地 `watch` $route 对象上的任意属性,在这个场景中,就是 $route.params : + 组合式API写法 ```html <script setup> import { watch } from 'vue' import { useRoute } from 'vue-router' const route = useRoute() watch( () => route.params.id, (newId, oldId) => { // 对路由变化做出响应... } ) </script> ``` + 选项式API写法 ```html <script> export default { created() { this.$watch( () => this.$route.params.id, (newId, oldId) => { // 对路由变化做出响应... } ) }, } </script> ``` 或者,使用 `beforeRouteUpdate` 导航守卫 + 组合式API写法 ```html <script setup> import { onBeforeRouteUpdate } from 'vue-router' // ... onBeforeRouteUpdate(async (to, from) => { // 对路由变化做出响应... userData.value = await fetchUser(to.params.id) }) </script> ``` + 选项式API写法 ```HTML <script> export default { async beforeRouteUpdate(to, from) { // 对路由变化做出响应... this.userData = await fetchUser(to.params.id) }, // ... } </script> ``` + **模板中路由参数是响应式的** ```HTML <script setup> import { useRoute } from 'vue-router' </script> <template> <!-- 模板中组件实例不会重复使用,vue 中路由参数在模板中是响应式的 --> <div>{{ route.params.name }}</div> <div>{{ $route.params.name }}</div> </template> ``` > **Tips:**组件实例将被重复使用只在 js 中有有效,在vue `template` 模板中是无效的,因为 vue 模板中 $route 和 useRoute() 都是响应式的,在模板中可以直接使用 $route/useRoute()即可刷新数据,但在js中就需要注意了,组件实例会被重复使用,所以要使用watch来监听路由参数的变化 ## 路由匹配 ### 在参数中自定义正则 当定义像 :userId 这样的参数时,我们内部使用以下的正则 ([^/]+) (至少一个不是斜杠 / 的字符)来从 URL 中提取参数。这很好用,除非你需要根据参数的内容来区分两个路由。想象一下,两个路由 /:orderId 和 /:productName,两者会匹配完全相同的 URL,所以我们需要一种方法来区分它们。最简单的方法就是在路径中添加一个静态部分来区分它们: ```js // 代码中省略了component参数 const routes = [ // 匹配 /o/3549 { path: '/o/:orderId' }, // 匹配 /p/books { path: '/p/:productName' }, ] ``` 但在某些情况下,我们并不想添加静态的 /o /p 部分。由于,orderId 总是一个数字,而 productName 可以是任何东西,所以我们可以在括号中为参数指定一个自定义的正则: ```js // 代码中省略了component参数 const routes = [ // /:orderId -> 仅匹配数字 { path: '/:orderId(\\d+)' }, // /:productName -> 匹配其他任何内容 { path: '/:productName' }, ] ``` 现在,转到 /25 将匹配 /:orderId,其他情况将会匹配 /:productName。`routes 数组的顺序并不重要!` > Tip 确保转义反斜杠( \ ),就像我们对 \d (变成\\d)所做的那样,在 JavaScript 中实际传递字符串中的反斜杠字符。 ### 可重复的参数(多参数) 如果你需要匹配具有多个部分的路由,如 /first/second/third,你应该用 `*`(0 个或多个)和 `+`(1 个或多个)将参数标记为可重复: ```js const routes = [ // /:chapters -> 匹配 /one, /one/two, /one/two/three, 等 { path: '/:chapters+' }, // /:chapters -> 匹配 /, /one, /one/two, /one/two/three, 等 { path: '/:chapters*' }, ] ``` 这将为你提供一个参数数组,而不是一个字符串,并且在使用命名路由时也需要你传递一个数组: ```js // 给定 { 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` 为空 ``` 这些也可以通过在右括号后添加它们与自定义正则结合使用: ```js const routes = [ // 仅匹配数字 // 匹配 /1, /1/2, 等 { path: '/:chapters(\\d+)+' }, // 匹配 /, /1, /1/2, 等 { path: '/:chapters(\\d+)*' }, ] ``` > Tips:理解为路由参数可以是一个数组,数组参数在浏览器地址栏以`/`开头,例如`/`、`/a`、`/a/b` ### 可选参数(0个或1个参数) 你也可以通过使用 ? 修饰符(0 个或 1 个)将一个参数标记为可选: ``` js const routes = [ // 匹配 /users 和 /users/posva { path: '/users/:userId?' }, // 匹配 /users 和 /users/42 { path: '/users/:userId(\\d+)?' }, ] ``` 请注意,`*` 在技术上也标志着一个参数是可选的,但 `?` 参数不能重复,`+` 至少有一个参数,下面是三个符号的对比 |浏览器 URL|是否匹配|$route.params 结果|说明| |--|--|--|--| |`?`|--|--|--| |/users|✅ 匹配|{}|不传参数,可选生效| |/users/123|✅ 匹配|{ userId: "123" }|传 1 个参数,正常匹配| |/users/123/456|❌ 不匹配|-|传 2 个参数,? 不允许重复| |`*`|--|--|--| |/|✅ 匹配|{ chapters: [] }|不传参数,空数组| |/vue|✅ 匹配|{ chapters: ["vue"] }|传 1 个参数| |/vue/router|✅ 匹配|{ chapters: ["vue", "router"] }|传 2 个参数(重复)| |/vue/router/guide|✅ 匹配|{ chapters: ["vue", "router", "guide"] }|传 3 个参数(重复)| |`+`|--|--|--| |/|❌ 不匹配|{ chapters: [] }|必须至少传 1 个| |/vue|✅ 匹配|{ chapters: ["vue"] }|传 1 个参数| |/vue/router|✅ 匹配|{ chapters: ["vue", "router"] }|传 2 个参数(重复)| |/vue/router/guide|✅ 匹配|{ chapters: ["vue", "router", "guide"] }|传 3 个参数(重复)| ### 捕获所有路由或 404 Not found 路由 常规参数只匹配 url 片段之间的字符,用 / 分隔。如果我们想匹配任意路径,我们可以使用自定义的 路径参数 正则表达式,在 路径参数 后面的括号中加入 正则表达式 : ``` js const routes = [ // 将匹配所有内容并将其放在 `route.params.pathMatch` 下 { path: '/:pathMatch(.*)*', name: 'NotFound', component: NotFound }, // 将匹配以 `/user-` 开头的所有内容,并将其放在 `route.params.afterUser` 下 { path: '/user-:afterUser(.*)', component: UserGeneric }, ] ``` 在这个特定的场景中,我们在括号之间使用了自定义正则表达式,并将pathMatch 参数标记为可选可重复。这样做是为了让我们在需要的时候,可以通过将 path 拆分成一个数组,直接导航到路由: ``` js router.push({ name: 'NotFound', // 保留当前路径并删除第一个字符,以避免目标 URL 以 `//` 开头。 params: { pathMatch: this.$route.path.substring(1).split('/') }, // 保留现有的查询和 hash 值,如果有的话 query: route.query, hash: route.hash, }) ``` ### strict 和 sensitive 匹配严格/宽松 两个配置**互不影响**,不是一对反义词 - strict:管 **末尾有没有 `/`**(比如 `/home` 和 `/home/` 算不算一样) - sensitive:管 **大小写**(比如 `/Home` 和 `/home` 算不算一样) > Tips:**内部路由规则 > 全局规则**(局部配置会覆盖全局) #### 全局配置(默认值) ```javascript const router = new VueRouter({ strict: false, // 默认:不严格检查末尾斜杠 sensitive: false, // 默认:不区分大小写 routes: [...] }) ``` #### strict 是否**严格匹配末尾斜杠 /** - **`strict: false`(默认)**: `/home` 和 `/home/` **视为同一个路由**输哪个都能匹配上 - **`strict: true`**:`/home` 和 `/home/` **是两个不同路由**必须完全一致才匹配 > 用途:统一 URL 格式,避免 SEO 认为是重复页面。 #### sensitive 是否**区分大小写** - **`sensitive: false`(默认)**`/home`、`/Home`、`/HOME`,**全都匹配** - **`sensitive: true`**只有**大小写完全一样**才算匹配,`/Home` 无法匹配 `/home` > 用途:严格规范 URL 大小写,避免用户乱输大小写也能进页面。 #### 全局 vs 内部 **规则:局部配置 100% 覆盖全局** 例子: ```javascript const router = new VueRouter({ strict: false, // 全局:不检查末尾 / sensitive: false, // 全局:不区分大小写 routes: [ { path: '/user', strict: true, // 局部:覆盖全局 → 必须严格匹配末尾 / sensitive: true, // 局部:覆盖全局 → 必须区分大小写 } ] }) ``` 结果: - 全局:宽松 - `/user` 这条路由:**超级严格** 最直观的匹配对照表 | 配置组合 | `/user` 能匹配 | `/user/` 能匹配 | `/User` 能匹配 | |-------------------------|----------------|-----------------|----------------| | 全局默认(都 false)| ✅ | ✅ | ✅ | | `strict: true` | ✅ | ❌ | ✅ | | `sensitive: true` | ✅ | ✅ | ❌ | | 两个都 true | ✅ | ❌ | ❌ |
扫一扫手机看
点击排行
windows 文件资源管理器使用
Layui 弹窗open使用说明
SQL Server 中字符串函数使用
C# 使用QQ邮箱代理做邮件接收功能
SQL Server关于apply的两种形式cross apply 和 outer apply
ASP.NET MVC 模型的自定义验证
nvm安装及常用命令
SQL Server 中数据类型转换
SQL Server 中WITH AS短语的使用
IE浏览器下AJAX缓存问题导致数据不更新的解决办法
订阅号