Sider菜单案例,把 md后缀修改为 zip,然后解压缩
image.pngSider.md

使用 Sider

  1. import Sider from '@layouts/Sider';
  2. const data = [
  3. {
  4. name: '仪表盘',
  5. icon: 'dashboard',
  6. path: '/dashboard', // before is 'dashboard'
  7. children: [
  8. {
  9. name: '分析页',
  10. path: '/dashboard/analysis', // before is 'analysis'
  11. children: [
  12. {
  13. name: '实时数据',
  14. path: '/dashboard/analysis/realtime', // before is 'realtime'
  15. },
  16. {
  17. name: '离线数据',
  18. path: '/dashboard/analysis/offline', // before is 'offline'
  19. },
  20. ],
  21. },
  22. ],
  23. },
  24. {
  25. name: '列表页',
  26. icon: 'list',
  27. path: '/list',
  28. },
  29. ];
  30. function App() {
  31. const { pathname } = props.location;
  32. return (
  33. <Sider
  34. pathname={pathname}
  35. menuData={data}
  36. />
  37. )
  38. }

Sider.jsx

  1. import React, { useState, useEffect } from 'react';
  2. import { number, string, array, arrayOf, shape } from 'prop-types';
  3. import { Link } from 'dva/router';
  4. import { Menu } from 'antd';
  5. import { getSelectedKeys } from './utils';
  6. const { SubMenu, Item } = Menu;
  7. // submenu keys of first level
  8. const rootSubmenuKeys = ["/dashboard", "/list", "/"];
  9. Sider.propTypes = {
  10. width: number,
  11. pathname: string,
  12. menuData: arrayOf(shape({
  13. name: string,
  14. path: string,
  15. icon: string,
  16. children: array,
  17. })),
  18. };
  19. Sider.defaultProps = {
  20. menuData: [],
  21. width: 200,
  22. pathname: '/',
  23. };
  24. function Sider(props) {
  25. const { menuData, pathname, width } = props;
  26. // 初始值不能为空,否则切换路由,菜单会先收起,然后在展开;有闪烁问题
  27. const [state, setState ] = useState(getSelectedKeys({menuData,pathname}));
  28. useEffect(update, [pathname, menuData]);
  29. function update() {
  30. const newKeys = getSelectedKeys({menuData,pathname});
  31. setState(newKeys)
  32. }
  33. function onOpenChange(keys) {
  34. // setState(prevState => ({...prevState, openKeys}));
  35. let openKeys = keys
  36. // 如果没找到
  37. const latestOpenKey = keys.find((key) => !state.openKeys.includes(key));
  38. if (!rootSubmenuKeys.includes(latestOpenKey)) {
  39. openKeys = keys;
  40. } else {
  41. openKeys = latestOpenKey ? [latestOpenKey] : []
  42. }
  43. setState(prevState => ({...prevState, openKeys}));
  44. }
  45. function renderMenu(data) {
  46. return data.map((item) => {
  47. const { children, path, name } = item;
  48. if (children && children.length) {
  49. return (
  50. <SubMenu
  51. key={path}
  52. title={
  53. <span>{name}</span>
  54. }
  55. >
  56. {renderMenu(children)}
  57. </SubMenu>
  58. );
  59. }
  60. return (
  61. <Item key={path}>
  62. <Link to={path} href={path}>
  63. <span>{name}</span>
  64. </Link>
  65. </Item>
  66. );
  67. })
  68. }
  69. const { openKeys, selectedKeys } = state;
  70. const MenuProps = {
  71. mode:'inline',
  72. theme:'dark',
  73. // inlineCollapsed: true, // 收起菜单
  74. openKeys, // 当前展开的 SubMenu菜单项
  75. selectedKeys, // 选中的菜单项 key 数组
  76. onOpenChange,
  77. }
  78. console.log('state', state)
  79. return (
  80. <div style={{ width }}>
  81. <Menu {...MenuProps}>
  82. {renderMenu(menuData)}
  83. </Menu>
  84. </div>
  85. );
  86. }
  87. export default Sider;

菜单闪烁问题

openKeys初始值不能为空数组
否则切换路由,菜单会先收起,然后在展开;有闪烁问题

  1. const [state, setState] = useState({
  2. openKeys: [],
  3. selectedKeys: [],
  4. });
  5. useEffect(update, [pathname, menuData]);
  6. function update() {
  7. const pathArray = getFlatMenuKeys(menuData);
  8. const selectedKeys = getMenuMatchKeys(pathArray, urlToList(pathname));
  9. setState({
  10. openKeys: selectedKeys,
  11. selectedKeys,
  12. });
  13. }