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
相关推荐
xjt_09012 分钟前
浅析Web存储系统
前端
foxhuli22940 分钟前
禁止ifrmare标签上的文件,实现自动下载功能,并且隐藏工具栏
前端
青皮桔1 小时前
CSS实现百分比水柱图
前端·css
失落的多巴胺1 小时前
使用deepseek制作“喝什么奶茶”随机抽签小网页
javascript·css·css3·html5
DataGear1 小时前
如何在DataGear 5.4.1 中快速制作SQL服务端分页的数据表格看板
javascript·数据库·sql·信息可视化·数据分析·echarts·数据可视化
影子信息1 小时前
vue 前端动态导入文件 import.meta.glob
前端·javascript·vue.js
青阳流月1 小时前
1.vue权衡的艺术
前端·vue.js·开源
样子20181 小时前
Vue3 之dialog弹框简单制作
前端·javascript·vue.js·前端框架·ecmascript
kevin_水滴石穿1 小时前
Vue 中报错 TypeError: crypto$2.getRandomValues is not a function
前端·javascript·vue.js
翻滚吧键盘1 小时前
vue文本插值
javascript·vue.js·ecmascript