SiderMenu.tsx 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. import { Layout } from 'antd';
  2. import classNames from 'classnames';
  3. import React, { Component, Suspense } from 'react';
  4. import Link from 'umi/link';
  5. import defaultSettings from '../../../config/defaultSettings';
  6. import PageLoading from '../PageLoading';
  7. import { BaseMenuProps } from './BaseMenu';
  8. import styles from './index.less';
  9. import { getDefaultCollapsedSubMenus } from './SiderMenuUtils';
  10. const BaseMenu = React.lazy(() => import('./BaseMenu'));
  11. const { Sider } = Layout;
  12. const { title } = defaultSettings;
  13. let firstMount: boolean = true;
  14. export interface SiderMenuProps extends BaseMenuProps {
  15. logo?: string;
  16. fixSiderbar?: boolean;
  17. }
  18. interface SiderMenuState {
  19. pathname?: string;
  20. openKeys?: string[];
  21. flatMenuKeysLen?: number;
  22. }
  23. export default class SiderMenu extends Component<SiderMenuProps, SiderMenuState> {
  24. static defaultProps: SiderMenuProps = {
  25. flatMenuKeys: [],
  26. location: window.location,
  27. onCollapse: () => void 0,
  28. isMobile: false,
  29. openKeys: [],
  30. collapsed: false,
  31. handleOpenChange: () => void 0,
  32. menuData: [],
  33. onOpenChange: () => void 0,
  34. };
  35. static getDerivedStateFromProps(props: SiderMenuProps, state: SiderMenuState) {
  36. const { pathname, flatMenuKeysLen } = state;
  37. if (props.location!.pathname !== pathname || props.flatMenuKeys!.length !== flatMenuKeysLen) {
  38. return {
  39. pathname: props.location!.pathname,
  40. flatMenuKeysLen: props.flatMenuKeys!.length,
  41. openKeys: getDefaultCollapsedSubMenus(props),
  42. };
  43. }
  44. return null;
  45. }
  46. constructor(props: SiderMenuProps) {
  47. super(props);
  48. this.state = {
  49. openKeys: getDefaultCollapsedSubMenus(props),
  50. };
  51. }
  52. componentDidMount() {
  53. firstMount = false;
  54. }
  55. isMainMenu: (key: string) => boolean = key => {
  56. const { menuData } = this.props;
  57. return menuData!.some(item => {
  58. if (key) {
  59. return item.key === key || item.path === key;
  60. }
  61. return false;
  62. });
  63. };
  64. handleOpenChange: (openKeys: string[]) => void = openKeys => {
  65. const moreThanOne = openKeys.filter(openKey => this.isMainMenu(openKey)).length > 1;
  66. if (moreThanOne) {
  67. this.setState({ openKeys: [openKeys.pop()].filter(item => item) as string[] });
  68. } else {
  69. this.setState({ openKeys: [...openKeys] });
  70. }
  71. };
  72. render() {
  73. const { logo, collapsed, onCollapse, fixSiderbar, theme, isMobile } = this.props;
  74. const { openKeys } = this.state;
  75. const defaultProps = collapsed ? {} : { openKeys };
  76. const siderClassName = classNames(styles.sider, {
  77. [styles.fixSiderBar]: fixSiderbar,
  78. [styles.light]: theme === 'light',
  79. });
  80. return (
  81. <Sider
  82. collapsible
  83. trigger={null}
  84. collapsed={collapsed}
  85. breakpoint="lg"
  86. onCollapse={collapse => {
  87. if (firstMount || !isMobile) {
  88. onCollapse!(collapse);
  89. }
  90. }}
  91. width={256}
  92. theme={theme}
  93. className={siderClassName}
  94. >
  95. <div className={styles.logo} id="logo">
  96. <Link to="/">
  97. <img src={logo} alt="logo" />
  98. <h1>{title}</h1>
  99. </Link>
  100. </div>
  101. <Suspense fallback={<PageLoading />}>
  102. <BaseMenu
  103. {...this.props}
  104. mode="inline"
  105. handleOpenChange={this.handleOpenChange}
  106. onOpenChange={this.handleOpenChange}
  107. style={{ padding: '16px 0', width: '100%' }}
  108. {...defaultProps}
  109. />
  110. </Suspense>
  111. </Sider>
  112. );
  113. }
  114. }