antd的MenuItem的icon属性值是一个ReactNode类型值,如果我们项目的菜单比较少,且是静态配置的话,倒还好,简单配置一下就好了,可大多数情况都不是简单的几个固定的菜单,而是从接口下发的带有权限菜单,那么这个时候就就麻烦了。
因为正常情况下,接口下发的菜单数据大概的数据结构应该类似:
[
{
"id": 1,
"path": "/orderList",
"text": "订单列表",
"icon": "BarChartOutlined"
},
{
"id": 2,
"path": "/report",
"text": "商品管理",
"icon": "CameraOutlined"
}
]
我们直接获取到的icon字段是一个字符串类型的,显然不符合antd中Menu.Item中icon属性值的类型要求,那怎么办呢?
既然icon属性需要一个ReactNode类型,那么我们就创建一个ReactNode类型吧.
// 创建icon图标元素
const iconToElement = (name: string) =>
React.createElement(Icon && (Icon as any)[name], {
style: { fontSize: '16px' }
})
这样,我们就可以在Menu.Item中去使用了:
<Menu.Item key={item.path} icon={item.icon ? iconToElement(item.icon) : ""}>
<Link to={item.path}>{item.text}</Link>
</Menu.Item>
当然了,我们在使用图标之前,需要先把图标库引入进来(假设我们使用的就是antd的默认图标库):
import * as Icon from "@ant-design/icons";
这样,就具有正常的使用接口下发的指定的icon了。
为了方便理解,贴一个整个的代码吧,有些代码是测试的,没有清理,凑合看下吧:
import React, { FC, useEffect, useState } from 'react';
import { Layout, Menu } from "antd";
import * as Icon from "@ant-design/icons";
const { Header, Content, Footer, Sider } = Layout;
const { SubMenu } = Menu;
import request from 'umi-request';
import logo from "../../assets/images/logo.png";
import style from "./less/layout2.less";
import { Link } from 'umi';
const MainLayout: FC = (props) => {
const [menu, setMenu] = useState([]);
const [defaultOpenKey, setDefaultOpenKey] = useState([]);
const getMenu = () => {
request.get("http://localhost:3000/menu").then(function (res) {
setDefaultOpenKey(res.defaultOpenKey);
setMenu(res.data);
}).catch(err => {
console.log(err);
})
}
useEffect(() => {
getMenu();
}, []);
// 创建icon图标元素
const iconToElement = (name: string) =>
React.createElement(Icon && (Icon as any)[name], {
style: { fontSize: '16px' }
})
return <div>
<Layout>
<Header className={style.header}>
<div className={style.logo}>
<img src={logo} alt="logo" />
</div>
</Header>
<Layout>
<Sider width={200} className="site-layout-background" theme="light">
<Menu mode='inline' defaultSelectedKeys={defaultOpenKey} defaultOpenKeys={defaultOpenKey} theme="light">
{
menu.map((item: any) => {
if (item.children && item.children.length > 0) {
return <SubMenu key={item.path} title={item.text} icon={item.icon ? iconToElement(item.icon) : ""}>
{
item.children.map((citem: any) => {
return <Menu.Item key={citem.path} icon={citem.icon ? iconToElement(citem.icon) : ""}>
<Link to={citem.path}>{citem.text}</Link>
</Menu.Item>
})
}
</SubMenu>
} else {
return (<Menu.Item key={item.path} icon={item.icon ? iconToElement(item.icon) : ""}>
<Link to={item.path}>{item.text}</Link>
</Menu.Item>
)
}
})
}
</Menu>
</Sider>
<Layout className={style.maincontentWraper}>
<Content className={style.maincontent} style={{ minHeight: '90vh' }}>
{props.children}
</Content>
</Layout>
</Layout>
</Layout>
</div>
}
export default MainLayout;
|