React(react-router-dom) 根据路径自动配置路由 延申

React(react-router-dom) 根据路径自动配置路由 延申

// app.js

import './App.css';
import { BrowserRouter as Router, Route, Redirect } from 'react-router-dom'
// 将 routerHandle 抽离
import { routerHandle } from './utils/common.tsx'

// 通过正则排除无需创建路由文件夹,这里排除的是 components 下包含的文件
const routers = require.context('./pages/', true, /^(?!.*\/(components)\/).*\.(tsx|jsx|js)$/)

function App() {
  return (
    <Router>
      <div className="App">
        {/* 默认路由匹配时,跳转到 /home 实现路由重定向到首页 */}
        <Route path="/" exact render={() => <Redirect to="/home" />} />
        {/* 路由 */}
        {routerHandle(routers)}
      </div>
    </Router>
  );
}

export default App;

// common.tsx
import { Route } from 'react-router-dom'

const COMPONENT_DIR = 'components/'

// 对比上一版,暂时先不做 toLowerCase() 处理
export function pathHandle(key: string) {
  let path = key
    .replace(/^\./, '')
    .replace(/\.(tsx|jsx|js)$/, '')
    .replace(/\/index(\[\w+])*$/, '$1')
    .replace(/\[(\w+)]/g, '/:$1')
    .replace(/\/\//g, '/')
  return path
}

function makeRouterMap(routers: any) {
  let routerMap = {} as any
  let keys = routers.keys()
  for (let key of keys) {
    let path = pathHandle(key)
    // 新增功能,配置自定义路由组件,通过使用文件夹 /(组件名称)/index.tsx 的方式标记文件,使用组件处理路由
    let Route = null
    // 判断是否包含括号
    if (path.indexOf('(') !== -1 && path.indexOf(')') !== -1) {
      // 取出组件名称
      let myRouteName = path.slice(path.indexOf('(') + 1, path.indexOf(')'))
      // 规定组件默认保存在 src/components 下
      Route = require('../' + COMPONENT_DIR + myRouteName)
    }
    // 去掉 path 的组件文件夹
    path = path.replace(/(\/\((\w+)\))/, '')
    routerMap[path] = {
      path,
      children: [],
      isTop: true,
      key,
      Route: Route?.default // 加入组件函数
    }
  }
  return routerMap
}

export function routerHandle(routers: any) {
  let routerMap = makeRouterMap(routers)
  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 = [] as any[]
  routerMapKeys.forEach(key => {
    let route = routerMap[key]
    if (route.isTop) {
      topRouters.push(route)
    }
  })
  return childrenRouteHandler(topRouters, routers)
}

export function childrenRouteHandler(items: any, routers: any) {
  return items.map((Item: any) => {
    let path = Item.path.toLowerCase()
    if (Item.children.length > 0) {
      // 循环时判断是否含有,自定义组件,有则使用自定义组件
      if (Item.Route) {
        return <Item.Route
          key={path}
          path={`${path}`}
          component={
            routers(Item.key).default.bind({
              childrenRoute: childrenRouteHandler(Item.children, routers)
            })
          }>
        </Item.Route>
      }
      return <Route
        key={path}
        path={`${path}`}
        component={
          routers(Item.key).default.bind({
            childrenRoute: childrenRouteHandler(Item.children, routers)
          })
        }>
      </Route>
    } else {
      if (Item.Route) {
        return <Item.Route
          key={path}
          exact
          path={`${path.replace(/\/default$/, '')}`}
          component={routers(Item.key).default} >
        </Item.Route>
      }
      return <Route
        key={path}
        exact
        path={`${path.replace(/\/default$/, '')}`}
        component={routers(Item.key).default} >
      </Route>
    }
  })
}
// src/components/AutoRoute/index.tsx

// 权限判断路由,判断用户是否登录,登录返回页面,未登录则跳到登录页面
import { Redirect, Route } from "react-router"
// 是否登录判断方法
import { isAuth } from "../../utils"

export default function AutoRoute({ component: Component, ...rest }: any) {
  // 注意,组件参数应, 完全按照 Route 保障统一
  return <Route
    {...rest}
    render={(props: any) => {
      return isAuth() ? (
        <Component {...props} />
      ) : (
        <Redirect
          to={{
            pathname: "/login",
            state: { from: props.location }
          }}
        />
      )
    }
    }
  />
}

// 配置文件路径, 例如,src/page/home/(AutoRoute)/test.tsx
// 生成路径 /home/test 同时使用 AutoRoute 包裹

补充

React(react-router-dom) 根据路径自动配置路由,第一版
React(react-router-dom) 根据路径自动配置路由,第三版

注意

嵌套子路由,包含在父级的 this 中,使用时务必,将其渲染,否则无效

配置方式针对函数组件

父级使用了路由组件会影响到子级,这点在第三版有处理

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
React Router是一个用于构建单页面应用程序的库。它提供了一种在React应用程序中管理路由的方式。React Router DOM是React Router的一个扩展,用于在Web应用程序中进行路由React Router DOM 5和React Router DOM 6之间有几个重要的区别: 1. 安装方式:React Router DOM 5使用npm包管理器进行安装,命令为`npm install react-router-dom`。而React Router DOM 6使用yarn进行安装,命令为`yarn add react-router-dom@next`。 2. 路由组件:在React Router DOM 5中,使用`<Route>`组件来定义路由。而在React Router DOM 6中,使用`<Route>`组件的替代方案`<Routes>`来定义路由。 3. 路由匹配方式:React Router DOM 5使用基于路径的匹配方式来确定哪个路由应该被渲染。而React Router DOM 6引入了新的匹配方式,称为元素匹配(element matching),它可以根据组件的类型来匹配路由。 4. 嵌套路由:在React Router DOM 5中,嵌套路由需要使用嵌套的`<Route>`组件来定义。而在React Router DOM 6中,可以使用嵌套的`<Routes>`组件来定义嵌套路由。 5. 动态路由:在React Router DOM 5中,可以通过在路径中使用参数来定义动态路由。而在React Router DOM 6中,可以使用`<Route>`组件的新属性`element`来定义动态路由。 6. 错误处理:React Router DOM 5使用`<Switch>`组件来处理路由匹配错误。而React Router DOM 6使用`<Routes>`组件的新属性`fallback`来处理路由匹配错误。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值