• React 像 vue 一样配置页面路由,并支持重定向路由,路由守卫等(使用 useRoutes 完成)


    • 希望达到跟 vue 一样,在 js 配置中则完成路由重定向的等基础操作,不太习惯使用 Routes、Route 等互相包裹的方式。

    • 所有基于 react-router-dom@6.15.0 封装了一个路由组件,并附带展示个路由守卫组件。

    • 路由组件 - ExRouter.tsx

      扩展路由配置,支持重定向,以及方便扩展其他属性。

      // 基于 react-router-dom@6.15.0 封装
      import { useRoutes, Navigate, RouteObject, IndexRouteObject, NonIndexRouteObject } from 'react-router-dom'
      import { useLocation, Location } from 'react-router'
      
      /**
       * @description: 扩展属性
       */
      interface ExRouteObjectProps {
        /**
         * @description: 重定向路由地址
         */
        redirect?: string,
        /**
         * @description: 子列表
         */  
        children?: ExRouteObject[]
      }
      
      /**
       * @description: 扩展 IndexRouteObject
       */
      export interface ExIndexRouteObject extends Omit<IndexRouteObject, 'children'>, ExRouteObjectProps {
      }
      
      /**
       * @description: 扩展 NonIndexRouteObject
       */
      export interface ExNonIndexRouteObject extends Omit<NonIndexRouteObject, 'children'>, ExRouteObjectProps {
      }
      
      /**
       * @description: 路由对象类型
       */
      export type ExRouteObject = ExIndexRouteObject | ExNonIndexRouteObject
      
      /**
       * @description: 找到路由对象类型
       */
      type ExRouteObjectFind = ExRouteObject | undefined
      
      /**
       * @description: 组件参数
       */
      export interface ExRouterProps {
        /**
         * @description: 路由列表
         */
        routes: ExRouteObject[]
      }
      
      const Component = (props: ExRouterProps) => {
        // 当前导航对象
        const location = useLocation()
        // 找到路由对象
        const findRoute = (routes: ExRouteObject[], location: Location): ExRouteObjectFind => {
          // 当前层级检查一轮
          let route: any = routes.find((item: any) => item.path === location.pathname)
          // 没有则搜索当前层级同级子页面
          if (!route) {
            // 排查,找到停止
            routes.some((item: any) => {
              // 取出子列表
              const children: ExRouteObject[] = item?.children || []
              // 子列表有值
              if (children.length) {
                // 进行排查
                route = findRoute(children, location) 
              }
              // 有值则暂停
              return !!route
            })
          }
          // 返回
          return route
        }
        // 找到当前路由
        const route: ExRouteObjectFind = findRoute(props.routes, location)
        // 返回渲染
        return (
          <>
            {/* 加载所有路由 */}
            { useRoutes(props.routes as RouteObject[]) }
            {/* 检查当前路由是否需要重定向 */}
            { route?.redirect && <Navigate to={route.redirect} replace /> }
          </>
        )
      }
      
      export default Component
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
      • 30
      • 31
      • 32
      • 33
      • 34
      • 35
      • 36
      • 37
      • 38
      • 39
      • 40
      • 41
      • 42
      • 43
      • 44
      • 45
      • 46
      • 47
      • 48
      • 49
      • 50
      • 51
      • 52
      • 53
      • 54
      • 55
      • 56
      • 57
      • 58
      • 59
      • 60
      • 61
      • 62
      • 63
      • 64
      • 65
      • 66
      • 67
      • 68
      • 69
      • 70
      • 71
      • 72
      • 73
      • 74
      • 75
      • 76
      • 77
      • 78
      • 79
      • 80
      • 81
      • 82
      • 83
      • 84
      • 85
      • 86
      • 87
      • 88
      • 89
    • 路由拦截(路由守卫)组件:

      // import { Navigate, useLocation, useSearchParams } from 'react-router-dom'
      
      const Component = (props: any) => {
        // // 接收路由参数
        // const [searchParams] = useSearchParams()
        // // 当前导航对象
        // const location = useLocation()
        // // token (检查本地或路由参数)
        // const token = 'xxxx'
        // // console.log(location, searchParams.get('token'))
        // // 路由权限校验
        // if (location.pathname.includes('/login') && token) {
        //   // 跳转登录页 && token有值
        //   return 
        // } else if (!location.pathname.includes('/login') && !token) {
        //   // 不是跳转登录页 && token无值
        //   return 
        // }
        // 验证通过
        return props.children
      }
      
      export default Component
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
    • 上面两个组件在路由中的使用:

      import React from 'react'
      import { ExRouteObject } from './ExRouter'
      import { Navigate } from 'react-router-dom'
      import BeforeEach from './BeforeEach'
      import ExRouter from './ExRouter'
      
      // 懒加载
      const lazyload = (path: string) => {
        // 加载组件
        let Component=React.lazy(()=>{return import (`@/${path}`)})
        // 返回渲染
        return (
          <React.Suspense fallback={<>请等待·····</>}>
            <Component />
          </React.Suspense>
        )
      }
      
      // 菜单路由
      export const menuRoutes: ExRouteObject[] = [
        {
          path: '/layout',
          redirect: '/layout/home',
          element: lazyload('layouts/BaseLayout'),
          children: [
            {
              path: '/layout/home',
              redirect: '/layout/home/home1',
              // element: lazyload('views/home'),
              children: [
                {
                  path: '/layout/home/home1',
                  element: lazyload('views/home')
                }
              ]
            }
          ]
        }
      ]
      
      // 路由列表
      const routes: Record<string, any>[] = [
        ...menuRoutes,
        {
          path: '/home',
          element: lazyload('views/home'),
        },
        {
          path: '/user',
          element: lazyload('views/user'),
        },
        {
          path: "/404",
          element: (<>页面地址不存在</>),
        },
        { path: "/", element: <Navigate to="/home" /> },
        { path: "*", element: <Navigate to="/404" /> },
      ]
      
      // 加载配置式路由
      function Router () {
        return (
          <BeforeEach>
            <ExRouter routes={routes}></ExRouter>
          </BeforeEach>
        )
      }
      
      // 导出
      export default Router
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
      • 30
      • 31
      • 32
      • 33
      • 34
      • 35
      • 36
      • 37
      • 38
      • 39
      • 40
      • 41
      • 42
      • 43
      • 44
      • 45
      • 46
      • 47
      • 48
      • 49
      • 50
      • 51
      • 52
      • 53
      • 54
      • 55
      • 56
      • 57
      • 58
      • 59
      • 60
      • 61
      • 62
      • 63
      • 64
      • 65
      • 66
      • 67
      • 68
      • 69
      • 70

      test.gif

  • 相关阅读:
    Python中的多线程(史上最简单易懂版)
    水平基准和垂直基准
    SummarizedExperiment 对象访问、操作和转换
    【面经】米哈游数据开发面经
    一天吃透Redis面试八股文
    HTTP vs RPC:理解两种通信协议的区别
    python系列笔记——常见运算符:算术运算符、比较运算符、赋值运算符、位运算符、逻辑运算符、成员运算符、身份运算符,及真题
    高考假期预习指南:开启你的IT学习之旅
    react-app-env.d.ts是什么?
    51单片机+DS1302设计一个电子钟(LCD1602显示时间)
  • 原文地址:https://blog.csdn.net/zz00008888/article/details/132970380