❤ React体系29-antd5左侧菜单最新版+Router(v6)实现(2024-06最新下)
之前我们写了左侧菜单的实现,在最新的版本之中菜单的方式写法已经进行进行了更改,接下来我们看看新旧的不同和如何实现并且优化
1、antd菜单新旧对比
老版本出现的情况
Warning: [antd: Menu] children
is deprecated. Please use items
instead.
官方建议
Ant Design 版进行了版本更新。由于 Ant Design 的菜单组件(Menu)在下一个主要版本中将删除 children
属性,并更改为 items
属性。
旧版本写法
4.20及以前版本Menu的写法
js
复制代码
<Menu mode="inline" theme="dark" defaultSelectedKeys={['1']} style={{ height: '100%', borderRight: 0 }}> <Menu.Item icon={<HomeOutlined />} key="1"> 数据概览 </Menu.Item> <Menu.Item icon={<DiffOutlined />} key="2"> 内容管理 </Menu.Item> <Menu.Item icon={<EditOutlined />} key="3"> 发布文章 </Menu.Item> </Menu>
新版本写法
更新之后不再在Menus组件之中写子节点,改成了直接通过属性items配置类型的添加
js
复制代码
//结构方面 <Menu defaultSelectedKeys={['1']} defaultOpenKeys={['sub1']} mode="inline" theme="dark" inlineCollapsed={collapsed} items={items} /> </> //配置item方面 const items = [ { key: '1', icon: <PieChartOutlined />, label: 'Option 1', }, { key: '2', icon: <DesktopOutlined />, label: 'Option 2', }, { key: 'sub1', label: 'Navigation One', icon: <MailOutlined />, children: [ { key: '5', label: 'Option 5', }, { key: '6', label: 'Option 6', }, { key: '7', label: 'Option 7', }, { key: '8', label: 'Option 8', }, ], }, ];
2、项目antd菜单最新写法(2024-06-05)
我们先看看新菜单里面的参数和作用
js
复制代码
- `defaultSelectedKeys`: 设置菜单的初始选中项。这个参数在初始化菜单时指定哪个菜单项是默认选中状态。 - `defaultOpenKeys`: 设置菜单的初始展开项。这个参数在初始化菜单时指定哪些菜单项是默认展开的。 - `selectedKeys`: 设置当前选中的菜单项。当用户点击菜单项时,这个参数用于更新当前选中的菜单项。 - `mode`: 设置菜单的模式,可以是 'vertical'(垂直)或 'horizontal'(水平)。 - `theme`: 设置菜单的主题,可以是 'light'(亮色)或 'dark'(暗色)。 - `onClick`: 指定菜单项点击事件的处理函数。当用户点击菜单项时,会调用这个函数进行相应的处理。 - `openKeys`: 控制菜单的展开状态。这个参数用于控制当前哪些菜单项是展开的。 - `onOpenChange`: 指定菜单展开/折叠事件的处理函数。当用户展开或折叠菜单项时,会调用这个函数进行相应的处理。 - `inlineCollapsed`: 设置菜单是否处于内联折叠状态。当菜单处于水平模式下,并且有子菜单时,可以通过这个参数控制菜单的折叠状态。 - `items`: 指定菜单项的配置信息。这个参数用于渲染菜单的具体内容。
上面这部分是官方给我们的写法,我们把他更改为自己的写法,这里大概是两种方式
第一种(重新组装为官方菜单)
第一种就是直接把我们数据组装一下,遍历赛进去,比较简单
js
复制代码
{ key: '1', icon: <PieChartOutlined />, label: 'Option 1', },
第二种 (采用-直接源路由改成官方参数方式)
我们是新项目,所以直接选择了源头更改,我直接把自己源路由改成了官方推荐的参数
然后引入和使用(这种处理真的是无脑且暴力)
js
复制代码
import routers,{adminRouter} from "@/router/index"; useEffect(() => { // setMenuList(items); setMenuList(adminRouter); }, []);
需要注意的是:
当我们没有内容的时候,进来不要写childern,像这种就是我写了空的children,或者自己进行一下筛选
点击菜单进行页面跳转
就是右边一个,加一个onClick事件
看一下官方的介绍
js
复制代码
onClick | 点击 MenuItem 调用此函数 | function({ item, key, keyPath, domEvent }) | | ------- | ----------------- | ------------------------------------------
然后我们尝试一下,先输出看看
js
复制代码
onClick={clickMenu} const clickMenu=({ item, key, keyPath, domEvent })=>{ console.log(item, key, keyPath, domEvent); }
这里我们可以看到,在我们这个props下包含了我们需要的所有信息,ok,这不就解决了我们需求吗
3、项目antd菜单点击跳转
js
复制代码
// 引入路由 import { Link, useLocation ,useNavigate} from 'react-router-dom'; let navigate=useNavigate(); // 进行跳转 const clickMenu=({ item, key, keyPath, domEvent })=>{ console.log(item, key, keyPath, domEvent); navigate(item.props.path); }
点击以后发现,我们的功能已经实现了!
回顾一下我们整个菜单的实现,其实也蛮简单的,就是左侧一个路由,然后右边其实相当于容器化的思想!
4、刷新不丢失菜单选中(刷新页面菜单保持用户之前的选中状态
)
导致问题
接下来我们针对菜单进行一部分优化,首先我们可以看到我们选择了角色以后,进行刷新,但是刷新以后发现菜单重新折叠并且还跑到了第一项
也就导致了这种情况:地址是角色的,展开的菜单确是首页的
这种应该如何处理呢
也就是我们需要实现用户进入界面默认展开所在区域二级菜单,加强用户体验
专业的说法就是刷新页面菜单保持用户之前的选中状态
处理问题
看看官方给我们提供的属性selectedKeys
这个时候我们可以用Menu的selectedKeys属性,官方的意思就是selectedKeys
表示当前样式所在的选中项key
思路:那我们就是把获取当前的路径拿到key然后给到selectedKeys
拿到当前页面的路径
(类组件),使用this.props.location.pathname
(函数式组件) 使用hooks的useLocation().pathname
我们这里直接上函数组件写法
js
复制代码
import { Link, useLocation ,useNavigate} from 'react-router-dom';// 如果你使用React Router const location = useLocation(); const [selectedKey, setSelectedKey] = useState(''); //选中的菜单刷新不丢失 const currentPath = location.pathname; useEffect(() => { setMenuList(adminRouter); console.log(currentPath,'currentPath'); setSelectedKey(currentPath); }) <Menu defaultSelectedKeys={['1']} defaultOpenKeys={['sub1']} selectedKeys={selectedKey} mode="inline" theme="dark" onClick={clickMenu} // openKeys={openKey} // inlineCollapsed={collapsed} items={menuList} > </Menu>
预览一下我们写法,报错
这是因为我们这个selectedKeys类型是string[]
更改一下我们的写法,最终的大致就是这样子
js
复制代码
import React, { useState, useEffect } from 'react'; import { Menu } from 'antd'; // 假设你正在使用Ant Design import { useLocation } from 'react-router-dom'; // 如果你使用React Router function MyMenu({ menuList }) { const location = useLocation(); const [selectedKey, setSelectedKey] = useState<string[]>(['']); // 使用字符串数组来匹配路径 useEffect(() => { const currentPath = location.pathname; const matchedMenu = menuList.find(item => item.path === currentPath); // 根据路径查找匹配的菜单项 if (matchedMenu) { setSelectedKey([matchedMenu.key]); // 更新选中的菜单项为匹配的菜单键 } }, [location.pathname, menuList]); const clickMenu = (e) => { // 处理菜单点击事件 }; return ( <Menu defaultSelectedKeys={['1']} defaultOpenKeys={['sub1']} selectedKeys={selectedKey} mode="inline" theme="dark" onClick={clickMenu} items={menuList} > {/* 渲染菜单项 */} </Menu> ); } export default MyMenu;
刷新以后ok,问题解决!
5、刷新时默认展开单个
当我们有多项菜单的时候可以发现,很多菜单都展开了,用户体验很不好,如何默认展开的菜单只有一项呢
如何达到这种效果呢 ,这个时候我们可以看看官方给我们提供的属性openKeys
和 onOpenChange
这个时候我们只需要添加一个展开项,同时在其他项点击的时候,
js
复制代码
import { Link, useLocation ,useNavigate} from 'react-router-dom';// 如果你使用React Router const [openKeys, setOpenKeys] = useState<string[]>(['']); const handleOpenChange = (keys: string[]) => { console.log(keys); setOpenKeys([keys[keys.length - 1]]); }; <Menu defaultSelectedKeys={['1']} defaultOpenKeys={['sub1']} selectedKeys={selectedKey} mode="inline" theme="dark" onClick={clickMenu} openKeys={openKeys} onOpenChange={handleOpenChange} items={menuList} > </Menu>
这个时候我们发现已经默认展开某一个了
6、刷新时默认展开选中项
我们刷新页面可以发现,页面的菜单又重新给这折叠了,根据我们正常的操作习惯,选中一个二级菜单节点的时候,刷新页面的时候应该保持用户之前的选中状态,并且二级菜单展开项应该默认展开。
配置展开项openKeys的初始值
js
复制代码
// 初始化菜单加载 const initMune=()=>{ let currentPath = location.pathname; //遍历路由表 adminRouter.map((itema) => { if(currentPath.indexOf(itema.path) === 0 ){ console.log(itema,'存在'); setOpenKeys([itema.key]); }else{ // console.log(itema,'不存在'); } }) } openKeys={openKeys} // 控制菜单的展开状态。这个参数用于控制当前哪些菜单项是展开的
这里我们菜单功能已经完结,散花!