- React 路由菜单学习 渲染
- 学习来源:juejin.cn/post/684490…
- 感谢 @秋天不落叶 博主 提供的开源模版
一、menu 菜单
react 中 菜单渲染, 参考and 能构建出大部分代码内容 其中 创建 渲染部分 大部分都以及完成
主要学习 动态路由渲染部分以及 路由持久化 处理 这里 没有采用mobx进行处理先采用了会话存储的方式进行
import React, { useEffect, useState } from "react"
import type { MenuProps } from "antd"
import { Menu } from "antd"
import { useNavigate, useLocation } from "react-router-dom"
/* icon */
import { HomeOutlined, ExperimentOutlined } from "@ant-design/icons"
import { commonRoutes } from "@/router/index"
import { ICommentRoutes, IRoute } from "@/types"
const MenuCom = () => {
const { pathname } = useLocation()
const navigate = useNavigate()
定义会话存储持久存储路由数据
-
1.通过定义 并转换 会话存储。
-
2再通过useState hook 进行 改变
/**
* @持久化存储
**/
//#region 持久化存储路由 / 路由组------------代码逻辑点击展开如下:===================》
const transOpenKey: string[] = sessionStorage.menuOpenKey ? JSON.parse(sessionStorage.menuOpenKey) : []
const transMenuSelectedKeys: string[] = sessionStorage.menuSelectedKeys ? JSON.parse(sessionStorage.menuSelectedKeys) : []
const [openKeys, setOpenKeys] = useState<string[]>(transOpenKey)
const [selectedKeys, setSelectedKeys] = useState<string[]>(transMenuSelectedKeys)
//#endregion
动态路由渲染
/**
* @路由渲染
**/
//#region 创建动态菜单逻辑------------代码如下:=======》
type MenuItem = Required<MenuProps>["items"][number]
function getItem(label: React.ReactNode, key: React.Key, icon?: React.ReactNode, children?: MenuItem[], type?: "group"): MenuItem {
return {
label,
key,
icon,
children,
type,
} as MenuItem
}
// icon 映射表
const iconObj: object = {
home: <HomeOutlined />,
test: <ExperimentOutlined />,
... 定义多个映射
}
路由示例如下:
function createMenuFn(commonRoutes: ICommentRoutes, isAlwaysShow?: boolean, onPath = "") {
const newItems: any = []
commonRoutes.forEach((route: IRoute) => {
if (route.alwaysShow || isAlwaysShow) {
// 多级目录
let frontPath = ""
if (!onPath) {
frontPath = route.path as string
} else {
frontPath = onPath + "/" + route.path
}
newItems.push(getItem(route.meta?.title, frontPath, route.meta?.icon && iconObj[route.meta?.icon], route.children && createMenuFn(route.children as any, true, frontPath)))
} else {
// 单级目录
route.children?.forEach((route2: IRoute) => {
newItems.push(getItem(route2.meta?.title, route2.path as string, iconObj[route2.meta?.icon as string]))
})
}
})
return newItems
}
const items: MenuItem[] = createMenuFn(commonRoutes as any)
//#endregion
/**
* @路由组切换
**/
const onOpenChange = (openKeys: string[]) => {
console.log("=======>openKeys", openKeys)
//存储路由组
setOpenKeys(openKeys)
sessionStorage.menuOpenKey = JSON.stringify(openKeys)
}
/**
* @菜单切换
**/
//#region:创建动态菜单逻辑 item 跳转路由 && 持久化 menu 选中------------代码如下:=======》
const navigateFn: MenuProps["onClick"] = (item) => {
// 路由跳转
navigate(item.key)
setSelectedKeys([item.key])
sessionStorage.menuSelectedKeys = JSON.stringify([item.key])
}
//#endregion
// 监听当前路径变化
useEffect(() => {
// 判断当前路径为多级menu时展开,单级menu时多级收缩
if (pathname.split("/").length > 3) {
setOpenKeys(transOpenKey)
}
if (pathname.split("/").length < 3) {
setOpenKeys([])
setSelectedKeys([])
}
// 控制menu选中变色
setSelectedKeys([pathname])
}, [pathname])
/**
* selectedKeys = activeRoutes 当前路由
* setOpenKeys = 路由组 当前选择的路由组(用于展开菜单)
**/
return <Menu theme="light" mode="inline" onClick={navigateFn} openKeys={openKeys} selectedKeys={selectedKeys} onOpenChange={onOpenChange} items={items} />
}
export default MenuCom