来,实现react-router里的match

461 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第12天,点击查看活动详情

前言

前面我们讲到在react-router-dom里,对于地址的匹配依托于path-to-regexp这个第三方库。

该库提供了多个方法,其中最主要的是pathToRegexp方法,而react-router里的match正是通过该方法去实现。

回顾

先看看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>
}

截屏2022-06-08 下午11.24.51.png

我们发现match对象里包含四个属性,可以通过被包裹的组件进行读取,分别是isExact(代表是否精确匹配)、params(代表地址匹配参数)、path(代表路径地址)、url(代表匹配到的路径)

实现

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匹配到的部分
    };
}

测试

在http://localhost:3000/blogId/123/a下运行下列代码:

import React from 'react'
import { BrowserRouter as Router, Route } from 'react-router-dom'
import {pathToRegexp} from "path-to-regexp"
impport pathMatch from "./pathMatch.js"

export default function App() {
  //测试代码:
  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)
  return (
    <Router>
      <Route path="/a" exact component={A} />
      <Route path="/b" component={B} />
      <Route path="/c" component={C} />
    </Router>
  )
}

function A(props) {
  return <h1>A</h1>
}

function B() {
  return <h1>B</h1>
}

function C() {
  return <h1>C</h1>
}

截屏2022-06-08 下午11.34.19.png

小结

在react-router内部,match的实现主要依托于path-to-regexp这个库,通过该库引入匹配规则和路径以及相关配置,即可获取包含路由信息的对象。