SliderMenu.js 3.18 KB
Newer Older
jiang's avatar
jiang committed
1
import React, { PureComponent } from 'react';
2
import { Layout } from 'antd';
jim's avatar
jim committed
3
import pathToRegexp from 'path-to-regexp';
jiang's avatar
jiang committed
4 5
import { Link } from 'dva/router';
import styles from './index.less';
Erwin Zhang's avatar
Erwin Zhang committed
6
import BaseMenu, { getMenuMatches } from './BaseMenu';
jim's avatar
jim committed
7
import { urlToList } from '../_utils/pathTools';
jiang's avatar
jiang committed
8

jim's avatar
jim committed
9
const { Sider } = Layout;
jiang's avatar
jiang committed
10

jim's avatar
jim committed
11 12 13 14 15
/**
 * θŽ·εΎ—θœε•ε­θŠ‚η‚Ή
 * @memberof SiderMenu
 */
const getDefaultCollapsedSubMenus = props => {
jim's avatar
jim committed
16 17
  const {
    location: { pathname },
ι™ˆεΈ…'s avatar
ι™ˆεΈ… committed
18
    flatMenuKeys,
jim's avatar
jim committed
19
  } = props;
jim's avatar
jim committed
20 21
  return urlToList(pathname)
    .map(item => {
ι™ˆεΈ…'s avatar
ι™ˆεΈ… committed
22
      return getMenuMatches(flatMenuKeys, item)[0];
jim's avatar
jim committed
23 24 25 26
    })
    .filter(item => item);
};

jim's avatar
jim committed
27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
/**
 * Recursively flatten the data
 * [{path:string},{path:string}] => {path,path2}
 * @param  menu
 */
export const getFlatMenuKeys = menu =>
  menu.reduce((keys, item) => {
    keys.push(item.path);
    if (item.children) {
      return keys.concat(getFlatMenuKeys(item.children));
    }
    return keys;
  }, []);

/**
 * Find all matched menu keys based on paths
 * @param  flatMenuKeys: [/abc, /abc/:id, /abc/:id/info]
 * @param  paths: [/abc, /abc/11, /abc/11/info]
 */
export const getMenuMatchKeys = (flatMenuKeys, paths) =>
  paths.reduce(
    (matchKeys, path) =>
      matchKeys.concat(flatMenuKeys.filter(item => pathToRegexp(item).test(path))),
    []
  );

jiang's avatar
jiang committed
53 54 55
export default class SiderMenu extends PureComponent {
  constructor(props) {
    super(props);
jim's avatar
jim committed
56
    this.flatMenuKeys = getFlatMenuKeys(props.menuData);
jiang's avatar
jiang committed
57
    this.state = {
jim's avatar
jim committed
58
      openKeys: getDefaultCollapsedSubMenus(props),
jiang's avatar
jiang committed
59 60
    };
  }
jim's avatar
jim committed
61

jim's avatar
jim committed
62 63 64 65 66 67 68 69 70 71
  static getDerivedStateFromProps(props, state) {
    const { pathname } = state;
    if (props.location.pathname !== pathname) {
      return {
        pathname: props.location.pathname,
        openKeys: getDefaultCollapsedSubMenus(props),
      };
    }
    return null;
  }
jim's avatar
jim committed
72
  isMainMenu = key => {
ι™ˆεΈ…'s avatar
ι™ˆεΈ… committed
73 74
    const { menuData } = this.props;
    return menuData.some(item => {
jim's avatar
jim committed
75 76 77 78 79
      if (key) {
        return item.key === key || item.path === key;
      }
      return false;
    });
jim's avatar
jim committed
80 81
  };
  handleOpenChange = openKeys => {
ddcat1115's avatar
ddcat1115 committed
82
    const moreThanOne = openKeys.filter(openKey => this.isMainMenu(openKey)).length > 1;
jiang's avatar
jiang committed
83
    this.setState({
jim's avatar
jim committed
84
      openKeys: moreThanOne ? [openKeys.pop()] : [...openKeys],
jiang's avatar
jiang committed
85
    });
86
  };
jiang's avatar
jiang committed
87
  render() {
88
    const { logo, collapsed, onCollapse, fixSiderbar, theme } = this.props;
89
    const { openKeys } = this.state;
jim's avatar
jim committed
90
    const defaultProps = collapsed ? {} : { openKeys };
jiang's avatar
jiang committed
91 92 93 94 95
    return (
      <Sider
        trigger={null}
        collapsible
        collapsed={collapsed}
96
        breakpoint="lg"
jiang's avatar
jiang committed
97 98
        onCollapse={onCollapse}
        width={256}
99 100 101
        className={`${styles.sider} ${fixSiderbar ? styles.fixSiderbar : ''} ${
          theme === 'light' ? styles.light : ''
        }`}
jiang's avatar
jiang committed
102
      >
103
        <div className={styles.logo} key="logo" id="logo">
jiang's avatar
jiang committed
104 105 106 107 108
          <Link to="/">
            <img src={logo} alt="logo" />
            <h1>Ant Design Pro</h1>
          </Link>
        </div>
Erwin Zhang's avatar
Erwin Zhang committed
109
        <BaseMenu
jim's avatar
jim committed
110
          {...this.props}
ι™ˆεΈ…'s avatar
ι™ˆεΈ… committed
111
          key="Menu"
jiang's avatar
jiang committed
112
          mode="inline"
jim's avatar
jim committed
113
          handleOpenChange={this.handleOpenChange}
jiang's avatar
jiang committed
114 115
          onOpenChange={this.handleOpenChange}
          style={{ padding: '16px 0', width: '100%' }}
jim's avatar
jim committed
116
          {...defaultProps}
jim's avatar
jim committed
117
        />
jiang's avatar
jiang committed
118 119 120 121
      </Sider>
    );
  }
}