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)
相关推荐
四喜花露水36 分钟前
Vue 自定义icon组件封装SVG图标
前端·javascript·vue.js
程序员爱技术5 小时前
Vue 2 + JavaScript + vue-count-to 集成案例
前端·javascript·vue.js
cs_dn_Jie10 小时前
钉钉 H5 微应用 手机端调试
前端·javascript·vue.js·vue·钉钉
开心工作室_kaic10 小时前
ssm068海鲜自助餐厅系统+vue(论文+源码)_kaic
前端·javascript·vue.js
有梦想的刺儿11 小时前
webWorker基本用法
前端·javascript·vue.js
customer0811 小时前
【开源免费】基于SpringBoot+Vue.JS周边产品销售网站(JAVA毕业设计)
java·vue.js·spring boot·后端·spring cloud·java-ee·开源
getaxiosluo12 小时前
react jsx基本语法,脚手架,父子传参,refs等详解
前端·vue.js·react.js·前端框架·hook·jsx
理想不理想v12 小时前
vue种ref跟reactive的区别?
前端·javascript·vue.js·webpack·前端框架·node.js·ecmascript
栈老师不回家13 小时前
Vue 计算属性和监听器
前端·javascript·vue.js
前端啊龙14 小时前
用vue3封装丶高仿element-plus里面的日期联级选择器,日期选择器
前端·javascript·vue.js