React - antd路由菜单 渲染

811 阅读2分钟
  1. React 路由菜单学习 渲染
  2. 学习来源:juejin.cn/post/684490…
  3. 感谢 @秋天不落叶 博主 提供的开源模版

一、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 进行 改变 image.png

  /**
   * @持久化存储
   **/
  //#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 />,
   ... 定义多个映射
  }

路由示例如下:

image.png



  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