react根据后端返回数据动态添加路由

以下代码都为部分核心代码

一.根据不同的登录用户,返回不同的权限列表 ,以下是三种不同用户限权列表

const pression = {
//超级管理员
  BigAdmin: [{
    key: "screen",
    icon: "FileOutlined",
    label: "数据图表",
  },
  {
    key: "users",
    icon: "UserOutlined",
    label: "用户列表",
  },
  {
    key: "food",
    icon: "PieChartOutlined",
    label: "食谱",

  },
  {
    key: "discuss",
    icon: "CommentOutlined",
    label: "评论",

  }],
//普通管理员
  Admin: [{
    key: "screen",
    icon: "FileOutlined",
    label: "数据图表",
  },

  {
    key: "food",
    icon: "PieChartOutlined",
    label: "食谱",

  }, {
    key: "discuss",
    icon: "CommentOutlined",
    label: "评论",

  }],
//普通用户
  commont: [
    {
      key: "screen",
      icon: "FileOutlined",
      label: "数据图表",
    }
  ]

}

二.实现动态菜单

用户登录后先将权限列表存入本地浏览器,再跳转到系统页面,并在首次加载时候获取本地权限列表数据,进行动态渲染

TypeScript 复制代码
//假如登录的是超级管理员,对应的权限列表应如下,这里使用了ant design的菜单组件,为了方便所以使用符合该菜单组件的数据结构
 BigAdmin: [{
    key: "screen",
    icon: "FileOutlined",
    label: "数据图表",
  },
  {
    key: "users",
    icon: "UserOutlined",
    label: "用户列表",
  },
  {
    key: "food",
    icon: "PieChartOutlined",
    label: "食谱",

  },
  {
    key: "discuss",
    icon: "CommentOutlined",
    label: "评论",

  }],
//-----------------


import * as Icons from '@ant-design/icons';

//--自定义组件将字符串转化为对应的组件---------
const ICONFONT = (props: any) => {
    const { icon } = props
    //动态菜单不能确定需要那些icon,全部引入作为Icons
    return React.createElement(Icons[icon])
}
  const [Enums, setenum] = useState<any>()
  const AdminInfo = useSelector((state: any) => state.AdminStore.AdminInfo)
useEffect(() => {
//登录后,系统首页获取本地权限列表,因为这里使用了ant design的icon,需要将字符串转化为对应的组件,这里封装的自定义组件
        let items = JSON.parse(JSON.stringify(AdminInfo.pression))
        items.map((item: any) => {
            item.icon = item.icon && <ICONFONT icon={item.icon}></ICONFONT>
        })
        setenum([...items])
    }, [])


//在菜单组件中使用
  <Menu selectedKeys={['screen']} mode="inline" items={Enums} onClick={chooose} />

三.实现动态路由

先把动态路由和静态路由分离出来,在路由配置文件中,这里需要进行动态添加的路由为 path: "/backstage"下的子路由,需要给他一个name,后续方便查找

TypeScript 复制代码
//这里也很重要,页面加载时候,先判断本地是否存入了权限列表
import { Admin } from "@/utils/local"
//获取本地存储的信息
const rs = Admin.get_Admin()


//路由懒加载
const lazyComponent = (Component: FC) => {
    return <Suspense fallback={Skeletons}>
        <Component />
    </Suspense>
}

//静态路由
const routers = [
    {
        path: '/',
        element: <Navigate to="/home" />
    },
    {
        path: "/",
        element: <App />,
        children: [
            {
                path: "/home",
                element: lazyComponent(Home),
            },
            {
                path: "/category",
                element: lazyComponent(About),
                children: [
                    {
                        path: "/category",
                        element: <Navigate to={'/category/mainfood'}></Navigate>
                    },
                    {
                        path: "mainfood",
                        element: lazyComponent(Mainfood)
                    },
                    {
                        path: "bake",
                        element: lazyComponent(Bake)
                    },
                    {
                        path: "beverage",
                        element: lazyComponent(Beverage)
                    },
                    {
                        path: "soup",
                        element: lazyComponent(Soup)
                    }
                ]
            }, {
                path: "/user",
                element: lazyComponent(Test),

            }, {
                path: "/edituser",
                element: lazyComponent(EeditUser)
            },
            {
                path: "/editfood",
                element: lazyComponent(Edit_Food)
            }

        ]
    },
    {
        path: "/detaile/:id",
        element: lazyComponent(Datile)
    },
    {
        path: "/login",
        element: <Login></Login>

    },
    {
//需要动态添加的路由在此处
        path: "/backstage",
        element: lazyComponent(Back),
        name: "back",
        children: [
            {
                path: "/backstage",
                element: <Navigate to="/backstage/screen"></Navigate>
            },
            {
                path: "screen",
                element: lazyComponent(Screen)
            },

        ]
    },
    {
        path: "*",
        element: <Error></Error>
    }
]


//准备需要添加的动态路由,将添加到 path: "/backstage"的子路由下,
//这里的id必须必须填写,而且必须唯一, 
//如:id:'4-2',4表示在一级路由下索引为4的路由,2表示在该路由下子路由的索引
const dtRoute = [
    {
        path: "users",
        element: lazyComponent(Users),
        id: '4-2'
    },
    {
        path: "food",
        id: '4-3',
        element: lazyComponent(Food)
    },
    {
        path: "discuss",
        id: '4-4',
        element: lazyComponent(Discuss)
    }
]

定义一个动态添加路由的函数

TypeScript 复制代码
const dtRoute = [
    {
        path: "users",
        element: lazyComponent(Users),
        id: '4-2'
    },
    {
        path: "food",
        id: '4-3',
        element: lazyComponent(Food)
    },
    {
        path: "discuss",
        id: '4-4',
        element: lazyComponent(Discuss)
    }
]

const route = createBrowserRouter(routers)

//这里需要导出函数,在登录后调用,pression即为后端返回的列表
export function addrouter(pression: any[]) {
//找到需要动态添加的路由,name为back,即为之前的path:"/backstage"路由
    const baseRouter = route.routes.find((rt: any) => rt.name === "back")
    console.log(baseRouter)
    if (pression.length !== 0) {

        //判断传入的权限列表是否在动态路由之中,有则追加进去
        for (const use of pression) {

            for (const rt of dtRoute) {
                if (rt.path === use.key) {
                    baseRouter?.children?.push(rt)
                } else {

                }
            }
        }
    } else {
//如果传入的为空表示,退出登录,更新路由,这里取的最前两个静态路由,即删除动态路由
        baseRouter?.children?.splice(2)
    }
}



//这里之前已提到,
import { Admin } from "@/utils/local"
const rs = Admin.get_Admin()
//-------页面刷新时候会重新执行路由文件---访问其它动态路由的时候会丢失找不到,
//因为动态路由只在登录的时候进行了添加,而页面刷新会让整个路由重新执行,而不会重新动态添加--
//所以刷新的时候要判断本地是否存储了动态路由信息,并再次添加
if (rs) {
    addrouter(rs.pression)
}

在redux中使用动态添加路由的函数

TypeScript 复制代码
import { createSlice } from "@reduxjs/toolkit";
import { Admin } from "@/utils/local";
import { Admin_Loing } from '@/apis/admin/admin'
import { message } from "antd"
import type { AppDispatch } from "../index"

//导入动态添加路由的函数
import { addrouter } from "@/router"
const AdminStore = createSlice({
    name: "RootStore",
    initialState: {
        AdminInfo: Admin.get_Admin() || {
            pression: [],
            user: {}
        }
    },
    reducers: {

//定义登录方法,需要在登录后动态添加路由
        Login: (state, { payload }) => {

            state.AdminInfo = payload

            Admin.set_Admin(payload)
//调用动态添加路由的函数,并传入登录后传来的权限列表
            addrouter(payload.pression)


        },
        GoOut: (state) => {
            state.AdminInfo = {
                pression: [],
                user: {}
            }
            Admin.remove_Admin()
            addrouter([])
        },

    },
})

//导出Login
export const { Login, GoOut } = AdminStore.actions


//,登录是异步的,所以定义异步登录方法
const axios_admin_login = (data: any) => {
    return async (dispatch: AppDispatch) => {
        const res = await Admin_Loing(data)
        if (res.status == 200) {
//登录成功后调用Login,并传入包含权限列表的数据
            dispatch(Login(res.data))
            message.success("登录成功")
            return true
        } else {
            return false
        }
    }
}
//最后导出异步登录,在登录界面使用
export { axios_admin_login }
export default AdminStore.reducer
相关推荐
Watermelo6178 分钟前
详解js柯里化原理及用法,探究柯里化在Redux Selector 的场景模拟、构建复杂的数据流管道、优化深度嵌套函数中的精妙应用
开发语言·前端·javascript·算法·数据挖掘·数据分析·ecmascript
m0_748248949 分钟前
HTML5系列(11)-- Web 无障碍开发指南
前端·html·html5
m0_7482356121 分钟前
从零开始学前端之HTML(三)
前端·html
一个处女座的程序猿O(∩_∩)O2 小时前
小型 Vue 项目,该不该用 Pinia 、Vuex呢?
前端·javascript·vue.js
hackeroink5 小时前
【2024版】最新推荐好用的XSS漏洞扫描利用工具_xss扫描工具
前端·xss
迷雾漫步者7 小时前
Flutter组件————FloatingActionButton
前端·flutter·dart
向前看-7 小时前
验证码机制
前端·后端
燃先生._.8 小时前
Day-03 Vue(生命周期、生命周期钩子八个函数、工程化开发和脚手架、组件化开发、根组件、局部注册和全局注册的步骤)
前端·javascript·vue.js
高山我梦口香糖9 小时前
[react]searchParams转普通对象
开发语言·前端·javascript