VueRouter@4 路由的匹配语法(自定义正则)

简介

我在学习 vue-router@4 动态路由中自定义正则匹配规则的时候遇到了几处误区,以我"钻牛角尖"的性格,查阅相关文档后,初见其中原理,特写下这篇文章。本篇文章默认读者已初步了解动态路由及正则表达式的基本知识。

动态路由参数

以下面路由为例,当路径出现 /:[name] 时,表明该路由是动态路由,将匹配以/开头的任意路由,如 /a/dasdas 等。在模板中通过 $route.params.pathName 可以获取动态参数。

js 复制代码
const routes = [
    {
        // 动态字段以冒号开始,对应路径的参数将赋值给pathName
        // 如路径 /abcd, 则pathName的值为abcd
        path: '/:pathName' 
    }
]

由于动态路由在匹配的时候不区分动态参数名,因此以路径 /abcd 访问以下路由的时候,匹配的永远是第一条路由。

js 复制代码
const routes = [
    {
        path: '/:pathName1' 
    },
    {
        path: '/:pathName2' 
    }
]

若要加以区分,则可添加路径前缀,如下所示。

js 复制代码
const routes = [
    {
        // 匹配 /a/abcd
        path: '/a/:pathName1' 
    },
    {
        // 匹配 /b/abcd
        path: '/b/:pathName2' 
    }
]

但这样就平白多出了路由前缀,不够简洁,因此引出了自定义正则。

在参数中自定义正则

若定义的路由出现 :[name],则在底层中会将其转化为正则表达式 ([^/]+) (匹配至少一个不是/的字符),如下。

当出现路由 /abcd ,则该路由就会与转化的正则相匹配,然后根据动态参数的位置,将对应位置的动态参数abcd赋值给pathName。

js 复制代码
const routes = [
    {
        // 底层转化为  /^\/([^/]+)/i,注意表达式并非完整,只是便于观看
        path: '/:pathName'   // 模板中$route.params.pathName -> abcd
    }
]

由上面例子所知,如果有多条一级的动态路由,我们又不想添加路由前缀,则可以使用自定义正则,自定义正则的形式为/:pathName(正则),通过在动态路径后添加括号,在括号中为参数指定一个自定义的正则,指定的自定义正则将会替代默认的 ([^/]+), 如下所示。

js 复制代码
const routes = [
    {
        // 底层转化为 /^\/(\d+)/i,注意表达式并非完整,只是便于观看
        path: '/:pathName(\\d+)'   // 仅匹配数字
    },
    {
        // 底层转化为 /^\/(.*)/i,注意表达式并非完整,只是便于观看
        path: '/:pathName(.*)'   // 匹配任意字符
    },
    {
        // 底层转化为 /^\/([^/]+)/i,注意表达式并非完整,只是便于观看
        path: '/:pathName'   // 匹配至少有一个不是斜杠的字符
    }
]

TIP

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

可重复参数

到这里我们就基本了解了什么是自定义正则了,但是我们在写下动态路由时,在底层中转化的正则表达式并非是全局匹配的,这也是为什么在上面的正则中出现i的原因。

从下面的例子看,我们以/assdf访问的时候,可以正确的匹配到 /:pathName ,但我们以 /asss/sss访问的时候,则无法匹配到 /:pathName 了,

js 复制代码
const routes = [
    {
        // 底层转化为 /^\/([^/]+)/i,注意表达式并非完整,只是便于观看
        path: '/:pathName'   // 匹配至少有一个不是斜杠的字符
        // /asss/sss 当出现了另一个斜杠,则匹配终止了,因此整个表达式不匹配
    }
]

为了匹配具有多个部分的路由,则需要使用到自定义正则的重复参数。 如 /abcd/ab, 我们需要用 *(0 个或多个)和 +(1 个或多个)将参数标记为可重复:

js 复制代码
const routes = [
    {
        // 底层转化为 /^\/((?:[^/]+?)(?:\/(?:[^/]+?))*)\/?$/i  完整表达式
        path: '/:pathName+'   // 多部分匹配至少有一个不是斜杠的字符(1个或多个)
                              // 匹配 /a,/a/b/c 。。。
    },
    {
        // 底层转化为 /^(?:\/((?:[^/]+?)(?:\/(?:[^/]+?))*))?\/?$/i 完整表达式
        path: '/:pathName*'   // 多部分匹配至少有一个不是斜杠的字符(0个或多个)
                              // 匹配 / ,/a,/a/b/c 。。。
    }
]

TIP

  1. 正则表达式中 (?:x)为非捕获括号,如果表达式是 /foo{1,2}/{1,2} 将只应用于 'foo' 的最后一个字符 'o'。如果使用非捕获括号,则 {1,2} 会应用于整个 'foo' 单词。

  2. ? 如果紧跟在任何量词 *+?{} 的后面 ,将会使量词变为非贪婪 (匹配尽量少的字符),和缺省使用的贪婪模式 (匹配尽可能多的字符)正好相反。例如,对 "123abc" 使用 /\d+/ 将会匹配 "123",而使用 /\d+?/ 则只会匹配到 "1"。如果不是跟着量词后面的话,则表示为0次或1次。

详情请移步MDN查阅:(developer.mozilla.org/zh-CN/docs/...)

当采用重复参数后,动态参数则以数组的形式接受多部分动态参数,如下:

js 复制代码
const routes = [
    {
        // 底层转化为 /^\/((?:[^/]+?)(?:\/(?:[^/]+?))*)\/?$/i  完整表达式
        // 匹配   /a/b/c
        path: '/:pathName*'   // $route.params.pathName -> ['a','b','c']
    }
]

/:path* 、/:path(.*)与 /:path(.*)*

好了,到了"钻牛角尖"的时候了,请问上面小标题的三个例子有什么区别? 如果看完这篇文章的话那么心里大致就有了答案了。

  • /:pathName* 是多部分匹配动态参数,若访问路径为 /a/b/c ,则获取到的参数为 ['a','b','c'] ;若访问路径为 /a//// ,则无法正常匹配。
  • /:pathName(.*) 是自定义正则,用 (.*) 去替换 ([^/]+),因此匹配的字符是包括/的,所以哪怕路径是 /ab//b//, 那么也是可以成功匹配的,得到的参数为 ['ab//b//']
  • /:pathName(.*)* 同理,也是可以匹配到 /ab//b//,但是匹配的是多部分的,区别就在于,匹配得到的参数为 [ "ab", "", "b", "", "" ]

这也是为什么官方推荐用 /:pathName(.*)* 来捕获404路由,这可以极大限度地来防止 "老六" 乱输路径。

js 复制代码
const routes = [
    {
        // 底层转化为 /^\/((?:[^/]+?)(?:\/(?:[^/]+?))*)\/?$/i  完整表达式
        path: '/:pathName*'
    },
    {
        // 底层转化为 /^\/(.*)\/?$/i 完整表达式
        path: '/:pathName(.*)'
    },
    {
        // 底层转化为 /^(?:\/((?:.*)(?:\/(?:.*))*))?\/?$/i 完整表达式
        path: '/:pathName(.*)*'
    }
]

相关参考

  1. 本篇文章针对路径的正则转化均来自官方推荐网站:Vue Router Path Parser (esm.dev)
  2. 正则相关知识:正则表达式 - JavaScript | MDN (mozilla.org)
  3. VueRouter官方文档:路由的匹配语法 | Vue Router (vuejs.org)
相关推荐
花花鱼4 分钟前
@antv/x6 导出图片下载,或者导出图片为base64由后端去处理。
vue.js
流烟默22 分钟前
Vue中watch监听属性的一些应用总结
前端·javascript·vue.js·watch
蒲公英10012 小时前
vue3学习:axios输入城市名称查询该城市天气
前端·vue.js·学习
杨荧4 小时前
【JAVA开源】基于Vue和SpringBoot的旅游管理系统
java·vue.js·spring boot·spring cloud·开源·旅游
一 乐9 小时前
学籍管理平台|在线学籍管理平台系统|基于Springboot+VUE的在线学籍管理平台系统设计与实现(源码+数据库+文档)
java·数据库·vue.js·spring boot·后端·学习
小御姐@stella10 小时前
Vue 之组件插槽Slot用法(组件间通信一种方式)
前端·javascript·vue.js
万叶学编程13 小时前
Day02-JavaScript-Vue
前端·javascript·vue.js
积水成江16 小时前
关于Generator,async 和 await的介绍
前端·javascript·vue.js
计算机学姐16 小时前
基于SpringBoot+Vue的高校运动会管理系统
java·vue.js·spring boot·后端·mysql·intellij-idea·mybatis
老华带你飞16 小时前
公寓管理系统|SprinBoot+vue夕阳红公寓管理系统(源码+数据库+文档)
java·前端·javascript·数据库·vue.js·spring boot·课程设计