目录
- 1,作用
- 2,实现获取 match 对象
- 2.1,match 对象的内容
- 2.2,注意点
- 2.3,实现
1,作用
之前在介绍 2.3 match 对象 时,提到了 react-router 使用第3方库 path-to-regexp 来匹配路径正则。
我们也利用它(版本v6.2.2),来手动实现一个获取类似 match
对象的方法。
2,实现获取 match 对象
2.1,match 对象的内容
- 不匹配时,返回
null
。 - 匹配时,返回一个对象
比如对下面的路由组件来说,
<Route path="/news/:id" component={News}></Route>
当访问 http://localhost:5173/news/123
时,返回的对象:
{
"path": "/news/:id",
"url": "/news/123",
"isExact": true,
"params": {
"id": "123"
}
}
2.2,注意点
先做个测试,看下返回内容。
import { pathToRegexp } from "path-to-regexp";
const path = "/news/:id";
const keys = [];
const regExp = pathToRegexp(path, keys);
console.log(regExp);
const result = regExp.exec(location.pathname);
console.log(result);
console.log(keys);
regExp
一个正则对象,
/^\/news(?:\/([^\/#\?]+?))[\/#\?]?$/i
result
匹配的结果,
[
"/news/123",
"123"
]
keys
的结果,
[
{
"name": "id",
"prefix": "/",
"suffix": "",
"pattern": "[^\\/#\\?]+?",
"modifier": ""
}
]
除了 match.isExact
属性,其他的东西都有了。而 match.isExact
可通过 location.pathname === result[0]
判断。
另外,还需要注意一点,<Route>
组件可以设置 exact
来表示是否精确匹配。比如,
<Route path="/news/:id" exact></Route>
此时访问 http://localhost:5173/news/123/xxx
是并不匹配,match
为 null
。
而 path-to-regexp 的默认配置项,是匹配到路径字符串结尾。所以这个配置项就相当于 exact
。
2.3,实现
import { pathToRegexp } from "path-to-regexp";
/**
* 返回一个类似 match 的对象。
* @param {*} path 路径规则
* @param {*} pathname 真实的地址
* @param {*} options react-router-dom 的 Route 组件的配置项。
*/
export default function matchPath(path, pathname, options) {
const keys = [];
const regExp = pathToRegexp(path, keys, getOptions(options));
const result = regExp.exec(pathname);
if (!result) {
return null;
}
const params = getParams(result.slice(1), keys);
return {
path,
url: result[0],
isExact: pathname === result[0],
params,
};
}
/**
* 返回符合 path-to-regexp 的配置项属性。
* @param {*} options
* @returns
*/
function getOptions(options = {}) {
const defaultOptions = {
exact: false, // 不精确匹配
sensitive: false, // 大小写敏感
strict: false, // 严格模式
};
const opts = {
...defaultOptions,
...options,
};
return {
end: opts.exact, // 更改 key
sensitive: opts.sensitive,
strict: opts.strict,
};
}
function getParams(result, keys) {
const obj = {};
keys.forEach((f, index) => {
obj[f.name] = result[index];
});
return obj;
}
测试1,
const match = pathMatch("/news/:id/:no", location.pathname);
当访问 http://localhost:5173/news/123/asd
时返回,
{
"path": "/news/:id/:no",
"url": "/news/123/asd",
"isExact": true,
"params": {
"id": "123",
"no": "asd"
}
}
测试2,
const match = pathMatch("/news/:id/:no", location.pathname);
当访问 http://localhost:5173/news/123/asd/xxx
时返回,
{
"path": "/news/:id/:no",
"url": "/news/123/asd",
"isExact": false,
"params": {
"id": "123",
"no": "asd"
}
}
以上。