百科狗-知识改变命运!
--

动态路由 - $route.params、$route.query、$route.path、$route.has - vue router(路由)

梵高1年前 (2023-11-21)阅读数 15#技术干货
文章标签路由

动态路由

很多时候,我们需要将给定匹配模式的路由映射到同一个组件。例如,我们可能有一个 User 组件,它应该对所有用户进行渲染,但用户 ID 不同。在 Vue Router 中,我们可以在路径中使用一个动态段来实现,我们称之为路径参数

const User = {
  template: '
User
', } // 这些都会传递给 `createRouter` const routes = [ // 动态段以冒号开始 { path: '/users/:id', component: User }, ]

现在像/users/johnny和/users/jolyne这样的 URL 都会映射到同一个路由。

路径参数,用:(冒号)表示。当一个路由被匹配时,它的params的值,将在每个组件中,以this.$route.params的形式暴露出来。因此,我们可以通过更新 User 的模板来呈现当前的用户 ID:

const User = {
    template: '
User {{ this.$route.params.id }}
' }

你可以在一个路由中设置多个路径参数,对应的值都会设置到$route.params中。例如:

模式匹配路径$route.params
/user/:username/user/evan{username:'evan'}
/user/:username/post/:post_id/user/evan/post/123{username:'evan', post_id:'123'}

动态路由 - $route.params、$route.query、$route.path、$route.has - vue router(路由)

除了$route.params外,$route对象还公开了其他有用的信息,如$route.query(如果 URL 中存在参数)、$route.hash等。


响应路由参数的变化

使用带有参数的路由时需要注意的是,当用户从/users/johnny导航到/users/jolyne时,相同的组件实例将被重复使用。因为两个路由都渲染同个组件,比起销毁再创建,复用则显得更加高效。不过,这也意味着组件的生命周期钩子不会被调用。

要对同一个组件中参数的变化做出响应的话,你可以简单地watch$route对象上的任意属性,在这个场景中,就是$route.params

const User = {
  template: '...',
  created() { this.$watch(
      () => this.$route.params,
      (toParams, previousParams) => {
        // 对路由变化做出响应...
      }
    )
  },
}

或者使用beforeRouteUpdate导航守卫,它也可以取消导航:

const User = {
  template: '...',
  async beforeRouteUpdate(to, from) {
    // 对路由变化做出响应...
    this.userData = await fetchUser(to.params.id)
  },
}


路由的匹配语法

大多数应用都会使用/about这样的静态路由和/users/:userId这样的动态路由,就像我们刚才在动态路由匹配中看到的那样,但是 Vue Router 可以提供更多的方式!

TIP:为了简单起见,所有的路由都省略了 component 属性,只关注 path 值。

在参数中自定义正则

当定义像:userId这样的参数时,我们内部使用以下的正则([^/]+)(至少有一个字符不是斜杠/)来从 URL 中提取参数。这很好用,除非你需要根据参数的内容来区分两个路由。想象一下,两个路由/:orderId/:productName,两者会匹配完全相同的 URL,所以我们需要一种方法来区分它们。最简单的方法就是在路径中添加一个静态部分来区分它们:

const routes = [
  // 匹配 /o/3549
  { path: '/o/:orderId' },
  // 匹配 /p/books
  { path: '/p/:productName' },
]

但在某些情况下,我们并不想添加静态的/o/p部分。由于,orderId总是一个数字,而productName可以是任何东西,所以我们可以在括号中为参数指定一个自定义的正则:

const routes = [
  // /:orderId -> 仅匹配数字
  { path: '/:orderId(\\d+)' },
  // /:productName -> 匹配其他任何内容
  { path: '/:productName' },
]

现在,转到/25将匹配/:orderId,其他情况将会匹配/:productName。routes 数组的顺序并不重要!

确保转义反斜杠(\),就像我们对\d(变成\\d)所做的那样,在 JavaScript 中实际传递字符串中的反斜杠字符。


可重复的参数

如果你需要匹配具有多个部分的路由,如/first/second/third,你应该用*(0 个或多个)和+(1 个或多个)将参数标记为可重复。但*也标志着一个参数是可选的。

const routes = [
  // /:chapters ->  匹配 /one, /one/two, /one/two/three, 等
  { path: '/:chapters+' },
  // /:chapters -> 匹配 /, /one, /one/two, /one/two/three, 等
  { 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, 等
  { path: '/:chapters(\\d+)+' },
  // 匹配 /, /1, /1/2, 等
  { path: '/:chapters(\\d+)*' },
]


可选参数

你也可以通过使用?修饰符(0 个或 1 个),将一个参数标记为可选,但不能重复

const routes = [
  // 匹配 /users 和 /users/posva
  { path: '/users/:userId?' },

  // 匹配 /users 和 /users/42
  { path: '/users/:userId(\\d+)?' },
]


参数修饰符
修饰符含义对应数据
+1 个或多个字符串、数组
*0 个或多个字符串、数组
?0 个或 1 个字符串


Sensitive 与 strict 路由配置

默认情况下,所有路由是不区分大小写的,并且能匹配带有或不带有尾部斜线的路由。例如,路由/users将匹配/users/users/、甚至/Users/。这种行为可以通过strictsensitive选项来修改,它们可以既可以应用在整个全局路由上,又可以应用于当前路由上:

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
})


捕获所有路由或 404 Not found 路由

常规参数只匹配 url 片段之间的字符,用/分隔。如果我们想匹配任意路径,我们可以使用自定义的路径参数正则表达式,在路径参数后面的括号中加入正则表达式:

const routes = [
  // 将匹配所有内容并将其放在 `$route.params.pathMatch` 下
  { path: '/:pathMatch(.*)*', name: 'NotFound', component: NotFound },
  // 将匹配以 `/user-` 开头的所有内容,并将其放在 `$route.params.afterUser` 下
  { path: '/user-:afterUser(.*)', component: UserGeneric },
]

在这个特定的场景中,我们在括号之间使用了自定义正则表达式,并将pathMatch参数,标记为可选可重复。这样做是为了让我们在需要的时候,可以通过将path拆分成一个数组,直接导航到路由:

this.$router.push({
  name: 'NotFound',
  params: { pathMatch: this.$route.path.split('/') },
})

如果你正在使用历史模式,请务必按照说明正确配置你的服务器。


调试

如果你需要探究你的路由是如何转化为正则的,以了解为什么一个路由没有被匹配,或者,报告一个 bug,你可以使用路径排名工具。它支持通过 URL 分享你的路由。

鹏仔微信 15129739599 鹏仔QQ344225443 鹏仔前端 pjxi.com 共享博客 sharedbk.com

免责声明:我们致力于保护作者版权,注重分享,当前被刊用文章因无法核实真实出处,未能及时与作者取得联系,或有版权异议的,请联系管理员,我们会立即处理! 部分文章是来自自研大数据AI进行生成,内容摘自(百度百科,百度知道,头条百科,中国民法典,刑法,牛津词典,新华词典,汉语词典,国家院校,科普平台)等数据,内容仅供学习参考,不准确地方联系删除处理!邮箱:344225443@qq.com)

图片声明:本站部分配图来自网络。本站只作为美观性配图使用,无任何非法侵犯第三方意图,一切解释权归图片著作权方,本站不承担任何责任。如有恶意碰瓷者,必当奉陪到底严惩不贷!

内容声明:本文中引用的各种信息及资料(包括但不限于文字、数据、图表及超链接等)均来源于该信息及资料的相关主体(包括但不限于公司、媒体、协会等机构)的官方网站或公开发表的信息。部分内容参考包括:(百度百科,百度知道,头条百科,中国民法典,刑法,牛津词典,新华词典,汉语词典,国家院校,科普平台)等数据,内容仅供参考使用,不准确地方联系删除处理!本站为非盈利性质站点,本着为中国教育事业出一份力,发布内容不收取任何费用也不接任何广告!)