React(react-router-dom) 根据路径自动配置路由,简单处理
# 创建 create-react-app
npx create-react-app my-app
cd my-app
npm start
在 src 目录下创建页面文件夹,如 pages
# 安装 react-router-dom
yarn add react-router-dom@5.3.0
// app.js
import './App.css';
import { BrowserRouter as Router, Route, Redirect, Link } from 'react-router-dom'
// 使用 webpack 的 require.context 方法,导入检索需要配置的文件
// './pages/':目标文件夹
// true:是否检索子文件夹
// /\.(tsx|jsx|js)$/:文件名匹配正则
const routers = require.context('./pages/', true, /\.(tsx|jsx|js)$/)
// context module 会导出一个(require)函数
// 路径处理,如 ./home/index[id].tsx 会被处理为 /home/:id
// [] 表示路径参数
function pathHandle(key) {
let path = key
.replace(/^\./, '')
.replace(/\.(tsx|jsx|js)$/, '')
.replace(/\/index(\[\w+])*$/, '$1')
.replace(/\[(\w+)]/g, '/:$1')
.replace(/\/\//g, '/')
.toLowerCase()
return path
}
// 路由处理
function routerHandle() {
let routerMap = {}
// 通过 keys() 获取文件名列表
let keys = routers.keys()
// 生成 routerMap 对象
keys.forEach(key => {
let path = pathHandle(key)
routerMap[path] = {
path, // 路由配置
children: [], // 子路由
isTop: true, // 是否为最上级路由
key // 相对文件路径
}
})
let routerMapKeys = Object.keys(routerMap)
// 循环对象,匹配父子关系
routerMapKeys.forEach(key => {
let parentPath = key.replace(/\/:\w+$/, '').replace(/\/\w+$/, '')
let parent = routerMap[parentPath]
if (parent) {
routerMap[key].isTop = false
parent.children.push(routerMap[key])
}
})
let topRouters = []
// 获取最上级路由
routerMapKeys.forEach(key => {
let route = routerMap[key]
if (route.isTop) {
topRouters.push(route)
}
})
// 递归填充路由代码
return childrenRouteHandler(topRouters)
}
// 递归函数
function childrenRouteHandler(items) {
return items.map(item => {
if (item.children.length > 0) {
// routers(item.key).default 通过传入 key 执行 require 函数获取对应的文件内容
// 配置路由,将子路由(childrenRoute)通过 bind 的方式传入父级路由
return <Route key={item.path} path={`${item.path}`} component={routers(item.key).default.bind({ childrenRoute: childrenRouteHandler(item.children) })}></Route>
} else {
return <Route key={item.path} exact path={`${item.path}`} component={routers(item.key).default}></Route>
}
})
}
function App() {
routerHandle()
return (
<Router>
<div className="App">
{/* 执行 routerHandle 导入路由 */}
{routerHandle()}
</div>
</Router>
);
}
export default App;
// src/pages/Home/index.tsx 父级路由
// src/pages/Home/test1.tsx 子路由1
// src/pages/Home/test2.tsx 子路由2
export default function Home(this: any, props: any){
// 通过 this.childrenRoute 获取到子路由,导入即可
return (<>Home { this.childrenRoute } </>)
}
补充
react-router-dom - npm (npmjs.com)
require.context()语法在ts环境下的配置
npm i @types/webpack-env @types/node -D
缺点
目前没有实现,父孙路由关系,如 /aaa 和 /aaa/bbb/ccc,由于 /aaa/bbb/ccc 没有父级,便会自动识别为顶级路由,叶子节点使用了 exact 相当于两个顶级路由,不存在交集。
第二版
React(react-router-dom) 根据路径自动配置路由 延申