❤ 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} // 控制菜单的展开状态。这个参数用于控制当前哪些菜单项是展开的
这里我们菜单功能已经完结,散花!