import React, { Fragment, useState } from 'react'; import { withRouter, Switch, history } from 'umi'; import { Menu } from 'antd'; import * as Icon from '@ant-design/icons'; import routerConfig from '../../config/router.config'; const { SubMenu } = Menu; const getIcon = (iconName) => { const res = React.createElement(Icon[iconName], { style: { fontSize: '16px' }, }); return res; }; const getSubMenu = (routesData) => { routesData.map((item) => { return <Menu.Item key={item.path}>{item.name}</Menu.Item>; }); }; const getMenu = (routesData) => { const menuData = []; for (let i = 0; i < routesData.length; i += 1) { if (Object.prototype.hasOwnProperty.call(routesData[i], 'routes')) { menuData.push( <SubMenu key={routesData[i].path} title={routesData[i].name} icon={getIcon(routesData[i].icon)} > {getSubMenu(routesData[i].routes)} </SubMenu>, ); } else { menuData.push( <Menu.Item key={routesData[i].path} icon={getIcon(routesData[i].icon)}> {routesData[i].name} </Menu.Item>, ); } } return menuData; }; const CreateMenu = () => { const [levelOne] = routerConfig; const { routes } = levelOne; return <Fragment>{getMenu(routes)}</Fragment>; }; export default withRouter(({ children, location }) => { const [current, setCurrent] = useState(''); const handleClick = (e) => { history.push(e.key); setCurrent(e.key); }; return ( <div> <Menu onClick={handleClick} selectedKeys={[current]} mode="horizontal"> {CreateMenu()} </Menu> <div> <Switch location={location}>{children.props.children}</Switch> </div> </div> ); });
引入依赖
首先,代码导入了所需的React和umi库的相关组件,以及Ant Design的Menu
组件和图标库。同时,它还导入了一个名为routerConfig
的路由配置文件。
辅助函数
getIcon(iconName)
: 根据传入的图标名称,动态创建一个图标元素。getSubMenu(routesData)
: 遍历传入的路由数据,为每个路由创建一个Menu.Item
。但注意,这个函数有一个问题:它没有返回创建的元素数组,这意味着在调用此函数时不会得到任何输出(这个问题在后面的代码中需要修正)。getMenu(routesData)
: 遍历传入的路由数据,并根据是否有子路由来创建SubMenu
或Menu.Item
。这个函数调用了getIcon
和getSubMenu
来辅助创建菜单项。
CreateMenu 组件
CreateMenu
是一个函数式组件,它从routerConfig
中提取第一级的路由数据,并使用getMenu
函数来生成菜单项。这个组件返回一个包含所有生成的菜单项的Fragment
。
主组件
主组件是一个使用withRouter
高阶组件包装的函数式组件。withRouter
允许组件访问路由相关的props,如location
。
handleClick(e)
: 当菜单项被点击时,此函数会被调用。它使用history.push
来更改当前路由,并使用setCurrent
来更新当前选中的菜单项。- 在组件的渲染部分,首先使用
Menu
组件来渲染菜单,菜单项由CreateMenu
组件生成。然后,使用Switch
组件来渲染子路由。注意,这里直接将children.props.children
作为Switch
的子元素可能不是最佳实践,因为它假设children
总是一个具有children
属性的对象,这可能在某些情况下不成立。