文章目录
一、path-to-regexp简介
路由的匹配需要对路径进行正则匹配,而path-to-regexp这个库则提供了匹配的方法。
1. 第一个参数(必填):匹配规则
先看看库的使用
import {
pathToRegexp} from "path-to-regexp"
const result = pathToRegexp("api/blogId/:id")
console.log(result)
//输出结果是/^api\/blogId(?:\/([^\/#\?]+?))[\/#\?]?$/i,这是一个对象
尝试匹配路径
import {
pathToRegexp} from "path-to-regexp"
const result = pathToRegexp("api/blogId/:id")
console.log(result.exec("api/blogId/123"))
console.log(result.exec("api/blogId/123/"))
console.log(result.exec("/blogId/123"))
console.log(result.exec("api/blogId/123/456"))
控制台输出结果:
2. 第二个参数(可选),包含匹配路径关键字的数组
查看第二个参数的内容:
import {
pathToRegexp} from "path-to-regexp"
const keys = [];
const result = pathToRegexp("api/blogId/:id",keys)
console.log(result,keys)
查看打印结果:
通过打印的结果,我们会发现数组选项表示匹配到的内容,其中数组对象里的name表示匹配到的对应的地址参数key。
3. 第三个参数(可选),配置对象
1.sensitive:是否区分大小写,默认false
2.strict:是否启用严格模式,默认为false,当为true时不能匹配最后的斜杆“/”(如blogID/123/)
3.end:是否匹配到字符串的末尾,默认为true,在router里是通过isExact改变
4.start:当为true时,regexp将从字符串的开头匹配,默认值为true
5.delimiter:段的默认分隔符,例如[^/#?],其命名模式为(默认值:’/#?’)
6.endsWith :可选字符或字符列表,将其视为“结束”字符
7.encode:在插入RegExp之前对字符串进行编码的函数
8.prefixes :分析时自动考虑前缀的字符列表(默认值:./)
二、实现router里的match对象
1. 回顾路由给组件注入的参数
先看看router给切换组件注入的props有哪些,通过下列代码,我们进入http://localhost:3000/a页面,并查看控制台打印结果:
import React from 'react'
import {
BrowserRouter as Router,Route} from 'react-router-dom'
export default function App() {
return (
<Router>
<Route path="/a" exact component={
A} />
<Route path="/b" component={
B} />
<Route path="/c" component={
C} />
</Router>
)
}
function A(props){
console.log("props:",props)
return <h1>A</h1>
}
function B(){
return <h1>B</h1>
}
function C(){
return <h1>C</h1>
}
其中我们发现match对象里包含四个属性,可以通过被包裹的组件进行读取,分别是isExact(代表是否精确匹配)、params(代表地址匹配参数)、path(代表路径地址)、url(代表匹配到的路径)
2. 实现路由里的match对象
import {
pathToRegexp } from "path-to-regexp"
/**
* @param {String} path 路径规则
* @param {String} pathname 页面路径地址的pathname
* @param {Object} options 相关配置,{sensitive,strict,isExct,}
*/
export default function pathMatch(path,pathname, options) {
const keys = []; //保存路径规则
const defaultOptions = {
sensitive: false, //是否区分大小写
strict: false, //是否为严格模式
exact: false, //是否匹配到字符串末尾
} //定义默认值
options = {
...defaultOptions,
...options
} //混合覆盖成新配置
const newOptions = {
sensitive: options.sensitive,
strict: options.strict,
end: options.exact,
} //配置
const regExp = pathToRegexp(path, keys, newOptions) //库的使用
const result = regExp.exec(pathname) //获取匹配结果
if (!result) {
return;
} //没有匹配到结果,直接返回
let resultArray = Array.from(result) //转换成真数组
const paramsArray = resultArray.slice(1) //去除数组第一项
let params = {
}; //定义params对象
for (let i = 0; i < paramsArray.length; i++) {
params[keys[i]['name']] = paramsArray[i];
} //循环获得params对象
return {
isExact: pathname === result[0], //判断是否是精确匹配
params, //传入的路径规则
path, //匹配规则
url: result[0], //url地址上与params匹配到的部分
};
}
3. 测试手写的match函数
在http://localhost:3000/blogId/123/a下运行下列代码:
const res1 = pathMatch("/blogId/:id", "/blogId/123/a", {
exact: true, strict: true })
console.log("res1", res1)
const res2 = pathMatch("/blogId/:id", "/blogId/123/a", {
exact: false, strict: true })
console.log("res2", res2)
const res3 = pathMatch("/blogId/:id", "/blogId/123/a", {
exact: true, strict: false })
console.log("res3", res3)
const res4 = pathMatch("/blogId/:id", "/blogId/123/a", {
exact: false, strict: false })
console.log("res4", res4)
控制台打印结果如下:
在http://localhost:3000/blogId/123/下运行下列代码:
const res1 = pathMatch("/blogId/:id", "/blogId/123/", {
exact: true, strict: true })
console.log("res1", res1)
const res2 = pathMatch("/blogId/:id", "/blogId/123/", {
exact: false, strict: true })
console.log("res2", res2)
const res3 = pathMatch("/blogId/:id", "/blogId/123/", {
exact: true, strict: false })
console.log("res3", res3)
const res4 = pathMatch("/blogId/:id", "/blogId/123/", {
exact: false, strict: false })
console.log("res4", res4)
控制台打印结果如下:
在http://localhost:3000/blogId下运行下列代码:
const res1 = pathMatch("/blogId/:id", "/blogId", {
exact: true, strict: true })
console.log("res1", res1)
const res2 = pathMatch("/blogId/:id", "/blogId", {
exact: false, strict: true })
console.log("res2", res2)
const res3 = pathMatch("/blogId/:id", "/blogId", {
exact: true, strict: false })
console.log("res3", res3)
const res4 = pathMatch("/blogId/:id", "/blogId", {
exact: false, strict: false })
console.log("res4", res4)
控制台打印结果如下:
总结
match的实现主要依托于path-to-regexp这个库,通过该库导入匹配规则和路径以及相关配置,即可获取包含路由信息的对象。