StyledMenu ICE 风格导航

如果项目中使用的是 1.x 版本的基础组件(@alifd/next),请在左侧导航顶部切换组件版本。

安装方法

  1. 在命令行中执行以下命令npm install @icedesign/styled-menu@0.1.2 -S

ICE 导航组件,为页面和功能提供导航的菜单列表。底层基于 rc-menu 并做了 ICE Design 的样式改造。

何时使用

导航菜单是一个网站的灵魂,用户依赖导航在各个页面中进行跳转。一般分为顶部导航和侧边导航,顶部导航提供全局性的类目和功能,侧边导航提供多级结构来收纳和排列网站架构。

  1. <StyledMenu>
  2. <StyledMenu.Item>菜单项</StyledMenu.Item>
  3. <StyledMenu.SubMenu title="子菜单">
  4. <StyledMenu.Item>子菜单项</StyledMenu.Item>
  5. </StyledMenu.SubMenu>
  6. </StyledMenu>

API

Menu props

参数说明类型默认值
theme主题颜色string: light darklight
color支持 Colorful ICE 配色string: blue, green, orange, red, roseo
mode菜单类型,现在支持垂直、水平、和内嵌模式三种string: vertical horizontal inlinevertical
selectedKeys当前选中的菜单项 key 数组string[]
defaultSelectedKeys初始选中的菜单项 key 数组string[]
openKeys当前展开的 SubMenu 菜单项 key 数组string[]
defaultOpenKeys初始展开的 SubMenu 菜单项 key 数组
onOpenChangeSubMenu 展开/关闭的回调Function(openKeys: string[])noop
onSelect被选中时调Function({ item, key, selectedKeys })
onDeselect取消选中时调用,仅在 multiple 生效Function({ item, key, selectedKeys })-
onClick点击 menuitem 调用此函数,参数为 {item, key, keyPath},在 MenuItem 上面设置 onClick 无效function-
style根节点样式object
inlineIndentinline 模式的菜单缩进宽度number24
multiple是否允许多选booleanfalse

More options in rc-menu

StyledMenu.Item props

参数说明类型默认值
disabled是否禁用booleanfalse
keyitem 的唯一标志string

StyledMenu.SubMenu props

参数说明类型默认值
disabled是否禁用booleanfalse
key唯一标志string
title子菜单项值string|ReactNode
children子菜单的菜单项Array<MenuItem|SubMenu>
onTitleClick点击子菜单标题Function({ eventKey, domEvent })

StyledMenu.ItemGroup props

参数说明类型默认值
title分组标题string|ReactNode
children分组的菜单项MenuItem[]

StyledMenu.Divider

菜单项分割线,只用在弹出菜单内。

代码示例

水平的顶部导航菜单

水平的顶部导航菜单。

StyledMenu ICE 风格导航 - 图1

查看源码在线预览

  1. import React, { Component } from 'react';
  2. import ReactDOM from 'react-dom';
  3. import { Icon } from '@icedesign/base';
  4. import StyledMenu, {
  5. Item as MenuItem,
  6. SubMenu,
  7. ItemGroup as MenuItemGroup
  8. } from '@icedesign/styled-menu';
  9. class App extends Component {
  10. constructor(props) {
  11. super(props);
  12. this.state = {
  13. current: 'mail'
  14. };
  15. }
  16. handleClick = e => {
  17. console.log('刚刚点击的数据:', e);
  18. this.setState({
  19. current: e.key
  20. });
  21. };
  22. render() {
  23. return (
  24. <StyledMenu
  25. onClick={this.handleClick}
  26. // selectedKeys 决定当前哪一项被选中
  27. selectedKeys={[this.state.current]}
  28. mode="horizontal"
  29. >
  30. <MenuItem key="mail">
  31. <Icon type="pin" />导航一(默认选中状态)
  32. </MenuItem>
  33. <MenuItem key="linkicon">
  34. <a target="_blank" href="https://www.taobao.com/">
  35. <Icon type="email" />导航二(演示超链接外链)
  36. </a>
  37. </MenuItem>
  38. <MenuItem key="app" disabled>
  39. <Icon type="form" />导航三(禁用当前选项)
  40. </MenuItem>
  41. <SubMenu
  42. key="SubMenu"
  43. title={
  44. <span>
  45. <Icon type="discount" />导航四(附带下拉菜单)
  46. </span>
  47. }
  48. >
  49. <MenuItemGroup title="下拉分组一">
  50. <MenuItem key="setting:1">选项 1</MenuItem>
  51. <MenuItem key="setting:2">选项 2</MenuItem>
  52. </MenuItemGroup>
  53. <MenuItemGroup title="下拉分组二">
  54. <MenuItem key="setting:3">选项 3</MenuItem>
  55. <MenuItem key="setting:4">选项 4</MenuItem>
  56. </MenuItemGroup>
  57. </SubMenu>
  58. </StyledMenu>
  59. );
  60. }
  61. }
  62. ReactDOM.render(<App />, mountNode);

内嵌菜单

垂直菜单,子菜单内嵌在菜单区域。

StyledMenu ICE 风格导航 - 图2

查看源码在线预览

  1. import React, { Component } from 'react';
  2. import ReactDOM from 'react-dom';
  3. import { Icon } from '@icedesign/base';
  4. import StyledMenu, {
  5. Item as MenuItem,
  6. SubMenu,
  7. ItemGroup as MenuItemGroup
  8. } from '@icedesign/styled-menu';
  9. class Sider extends Component {
  10. handleClick = e => {
  11. console.log('click ', e);
  12. };
  13. render() {
  14. return (
  15. <StyledMenu
  16. onClick={this.handleClick}
  17. style={{ width: 240 }}
  18. defaultSelectedKeys={['1']}
  19. defaultOpenKeys={['sub1']}
  20. mode="inline"
  21. >
  22. <SubMenu
  23. key="sub1"
  24. title={
  25. <span>
  26. <Icon type="box" />
  27. <span>导航一</span>
  28. </span>
  29. }
  30. >
  31. <MenuItemGroup key="g1" title="Item 1">
  32. <MenuItem key="1">Option 1</MenuItem>
  33. <MenuItem key="2">Option 2</MenuItem>
  34. </MenuItemGroup>
  35. <MenuItemGroup key="g2" title="Item 2">
  36. <MenuItem key="3">Option 3</MenuItem>
  37. <MenuItem key="4">Option 4</MenuItem>
  38. </MenuItemGroup>
  39. </SubMenu>
  40. <SubMenu
  41. key="sub2"
  42. title={
  43. <span>
  44. <Icon type="download" />
  45. <span>导航二</span>
  46. </span>
  47. }
  48. >
  49. <MenuItem key="5">Option 5</MenuItem>
  50. <MenuItem key="6">Option 6</MenuItem>
  51. <SubMenu key="sub3" title="SubMenu">
  52. <MenuItem key="7">Option 7</MenuItem>
  53. <MenuItem key="8">Option 8</MenuItem>
  54. </SubMenu>
  55. </SubMenu>
  56. <SubMenu
  57. key="sub4"
  58. title={
  59. <span>
  60. <Icon type="play" />
  61. <span>导航三</span>
  62. </span>
  63. }
  64. >
  65. <MenuItem key="9">Option 9</MenuItem>
  66. <MenuItem key="10">Option 10</MenuItem>
  67. <MenuItem key="11">Option 11</MenuItem>
  68. <MenuItem key="12">Option 12</MenuItem>
  69. </SubMenu>
  70. </StyledMenu>
  71. );
  72. }
  73. }
  74. ReactDOM.render(<Sider />, mountNode);

只展开当前父级菜单

点击菜单,收起其他展开的所有菜单,保持菜单聚焦简洁。

StyledMenu ICE 风格导航 - 图3

查看源码在线预览

  1. import React, { Component } from 'react';
  2. import ReactDOM from 'react-dom';
  3. import { Icon } from '@icedesign/base';
  4. import StyledMenu, { Item as MenuItem, SubMenu } from '@icedesign/styled-menu';
  5. class Sider extends React.Component {
  6. state = {
  7. current: '1',
  8. openKeys: []
  9. };
  10. handleClick = e => {
  11. console.log('Clicked: ', e);
  12. this.setState({ current: e.key });
  13. };
  14. onOpenChange = openKeys => {
  15. const state = this.state;
  16. const latestOpenKey = openKeys.find(
  17. key => !(state.openKeys.indexOf(key) > -1)
  18. );
  19. const latestCloseKey = state.openKeys.find(
  20. key => !(openKeys.indexOf(key) > -1)
  21. );
  22. let nextOpenKeys = [];
  23. if (latestOpenKey) {
  24. nextOpenKeys = this.getAncestorKeys(latestOpenKey).concat(latestOpenKey);
  25. }
  26. if (latestCloseKey) {
  27. nextOpenKeys = this.getAncestorKeys(latestCloseKey);
  28. }
  29. this.setState({ openKeys: nextOpenKeys });
  30. };
  31. getAncestorKeys = key => {
  32. const map = {
  33. sub3: ['sub2']
  34. };
  35. return map[key] || [];
  36. };
  37. render() {
  38. return (
  39. <StyledMenu
  40. mode="inline"
  41. openKeys={this.state.openKeys}
  42. selectedKeys={[this.state.current]}
  43. style={{ width: 240 }}
  44. onOpenChange={this.onOpenChange}
  45. onClick={this.handleClick}
  46. >
  47. <SubMenu
  48. key="sub1"
  49. title={
  50. <span>
  51. <Icon type="print" />
  52. <span>Navigation One</span>
  53. </span>
  54. }
  55. >
  56. <MenuItem key="1">Option 1</MenuItem>
  57. <MenuItem key="2">Option 2</MenuItem>
  58. <MenuItem key="3">Option 3</MenuItem>
  59. <MenuItem key="4">Option 4</MenuItem>
  60. </SubMenu>
  61. <SubMenu
  62. key="sub2"
  63. title={
  64. <span>
  65. <Icon type="process" />
  66. <span>Navigation Two</span>
  67. </span>
  68. }
  69. >
  70. <MenuItem key="5">Option 5</MenuItem>
  71. <MenuItem key="6">Option 6</MenuItem>
  72. <SubMenu key="sub3" title="SubMenu">
  73. <MenuItem key="7">Option 7</MenuItem>
  74. <MenuItem key="8">Option 8</MenuItem>
  75. </SubMenu>
  76. </SubMenu>
  77. <SubMenu
  78. key="sub4"
  79. title={
  80. <span>
  81. <Icon type="bags" />
  82. <span>Navigation Three</span>
  83. </span>
  84. }
  85. >
  86. <MenuItem key="9">Option 9</MenuItem>
  87. <MenuItem key="10">Option 10</MenuItem>
  88. <MenuItem key="11">Option 11</MenuItem>
  89. <MenuItem key="12">Option 12</MenuItem>
  90. </SubMenu>
  91. </StyledMenu>
  92. );
  93. }
  94. }
  95. ReactDOM.render(<Sider />, mountNode);

垂直菜单

子菜单是弹出的形式。

StyledMenu ICE 风格导航 - 图4

查看源码在线预览

  1. import React, { Component } from 'react';
  2. import ReactDOM from 'react-dom';
  3. import { Icon } from '@icedesign/base';
  4. import StyledMenu, {
  5. Item as MenuItem,
  6. SubMenu,
  7. ItemGroup as MenuItemGroup
  8. } from '@icedesign/styled-menu';
  9. function handleClick(e) {
  10. console.log('click', e);
  11. }
  12. ReactDOM.render(
  13. <StyledMenu onClick={handleClick} style={{ width: 240 }} mode="vertical">
  14. <SubMenu
  15. key="sub1"
  16. title={
  17. <span>
  18. <Icon type="security" />
  19. <span>Navigation One</span>
  20. </span>
  21. }
  22. >
  23. <MenuItemGroup title="Item 1">
  24. <MenuItem key="1">Option 1</MenuItem>
  25. <MenuItem key="2">Option 2</MenuItem>
  26. </MenuItemGroup>
  27. <MenuItemGroup title="Iteom 2">
  28. <MenuItem key="3">Option 3</MenuItem>
  29. <MenuItem key="4">Option 4</MenuItem>
  30. </MenuItemGroup>
  31. </SubMenu>
  32. <SubMenu
  33. key="sub2"
  34. title={
  35. <span>
  36. <Icon type="stop" />
  37. <span>Navigation Two</span>
  38. </span>
  39. }
  40. >
  41. <MenuItem key="5">Option 5</MenuItem>
  42. <MenuItem key="6">Option 6</MenuItem>
  43. <SubMenu key="sub3" title="SubMenu">
  44. <MenuItem key="7">Option 7</MenuItem>
  45. <MenuItem key="8">Option 8</MenuItem>
  46. </SubMenu>
  47. </SubMenu>
  48. <SubMenu
  49. key="sub4"
  50. title={
  51. <span>
  52. <Icon type="office" />
  53. <span>Navigation Three</span>
  54. </span>
  55. }
  56. >
  57. <MenuItem key="9">Option 9</MenuItem>
  58. <MenuItem key="10">Option 10</MenuItem>
  59. <MenuItem key="11">Option 11</MenuItem>
  60. <MenuItem key="12">Option 12</MenuItem>
  61. </SubMenu>
  62. </StyledMenu>,
  63. mountNode
  64. );

主题

内建了多套主题,兜底的有两套 light|dark,默认 light

theme 为主题配置,有浅色系(默认)和深色系两个配置 light|dark

StyledMenu ICE 风格导航 - 图5

查看源码在线预览

  1. import React, { Component } from 'react';
  2. import ReactDOM from 'react-dom';
  3. import { Icon, Switch, Select } from '@icedesign/base';
  4. import StyledMenu, {
  5. Item as MenuItem,
  6. SubMenu,
  7. Divider
  8. } from '@icedesign/styled-menu';
  9. const { Option } = Select;
  10. class Sider extends Component {
  11. state = {
  12. theme: 'dark',
  13. current: '1'
  14. };
  15. changeTheme = value => {
  16. this.setState({
  17. theme: value ? 'dark' : 'light'
  18. });
  19. };
  20. handleClick = e => {
  21. this.setState({
  22. current: e.key
  23. });
  24. };
  25. render() {
  26. return (
  27. <div>
  28. <div style={{ display: 'flex', alignItems: 'center' }}>
  29. <span>设置色彩深度:</span>
  30. <Switch
  31. checked={this.state.theme === 'dark'}
  32. onChange={this.changeTheme}
  33. checkedChildren="Dark"
  34. unCheckedChildren="Light"
  35. />
  36. </div>
  37. <h2>horizontal 模式效果</h2>
  38. <StyledMenu
  39. theme={this.state.theme}
  40. onClick={this.handleClick}
  41. selectedKeys={[this.state.current]}
  42. mode="horizontal"
  43. >
  44. <SubMenu title={<span>附带子菜单</span>} key="1">
  45. <MenuItem key="1-1">
  46. <a href="http://taobao.com" target="_blank">
  47. 外链
  48. </a>
  49. </MenuItem>
  50. <MenuItem key="1-2">0-2</MenuItem>
  51. </SubMenu>
  52. <MenuItem>
  53. <a href="http://taobao.com" target="_blank">
  54. 外链无需分配 key
  55. </a>
  56. </MenuItem>
  57. <MenuItem key="3">普通菜单</MenuItem>
  58. <SubMenu title={<span>附带子菜单和分割线</span>} key="4">
  59. <MenuItem key="4-1">菜单</MenuItem>
  60. <Divider />
  61. <SubMenu key="4-2" title={<span>下级菜单</span>}>
  62. <MenuItem key="4-2-1">菜单</MenuItem>
  63. <SubMenu title={<span>下下级菜单</span>} key="4-2-2">
  64. <MenuItem key="4-2-2-1">菜单</MenuItem>
  65. <MenuItem key="4-2-2-2">菜单2</MenuItem>
  66. </SubMenu>
  67. </SubMenu>
  68. </SubMenu>
  69. <MenuItem disabled>禁用效果</MenuItem>
  70. <MenuItem key="4-3">普通菜单</MenuItem>
  71. </StyledMenu>
  72. <h2>vertical 模式效果</h2>
  73. <StyledMenu
  74. theme={this.state.theme}
  75. onClick={this.handleClick}
  76. selectedKeys={[this.state.current]}
  77. mode="vertical"
  78. style={{ width: 240 }}
  79. defaultOpenKeys={['sub1']}
  80. >
  81. <SubMenu title={<span>附带子菜单</span>} key="1">
  82. <MenuItem key="1-1">
  83. <a href="http://taobao.com" target="_blank">
  84. 外链
  85. </a>
  86. </MenuItem>
  87. <MenuItem key="1-2">0-2</MenuItem>
  88. </SubMenu>
  89. <MenuItem>
  90. <a href="http://taobao.com" target="_blank">
  91. 外链无需分配 key
  92. </a>
  93. </MenuItem>
  94. <MenuItem key="3">普通菜单</MenuItem>
  95. <SubMenu title={<span>附带子菜单和分割线</span>} key="4">
  96. <MenuItem key="4-1">菜单</MenuItem>
  97. <Divider />
  98. <SubMenu key="4-2" title={<span>下级菜单</span>}>
  99. <MenuItem key="4-2-1">菜单</MenuItem>
  100. <SubMenu title={<span>下下级菜单</span>} key="4-2-2">
  101. <MenuItem key="4-2-2-1">菜单</MenuItem>
  102. <MenuItem key="4-2-2-2">菜单2</MenuItem>
  103. </SubMenu>
  104. </SubMenu>
  105. </SubMenu>
  106. <MenuItem disabled>禁用效果</MenuItem>
  107. <MenuItem key="4-3">普通菜单</MenuItem>
  108. </StyledMenu>
  109. <h2>inline 模式效果</h2>
  110. <StyledMenu
  111. theme={this.state.theme}
  112. onClick={this.handleClick}
  113. selectedKeys={[this.state.current]}
  114. mode="inline"
  115. style={{ width: 240 }}
  116. defaultOpenKeys={['sub1']}
  117. >
  118. <SubMenu title={<span>附带子菜单</span>} key="1">
  119. <MenuItem key="1-1">
  120. <a href="http://taobao.com" target="_blank">
  121. 外链
  122. </a>
  123. </MenuItem>
  124. <MenuItem key="1-2">0-2</MenuItem>
  125. </SubMenu>
  126. <MenuItem>
  127. <a href="http://taobao.com" target="_blank">
  128. 外链无需分配 key
  129. </a>
  130. </MenuItem>
  131. <MenuItem key="3">普通菜单</MenuItem>
  132. <SubMenu title={<span>附带子菜单和分割线</span>} key="4">
  133. <MenuItem key="4-1">菜单</MenuItem>
  134. <Divider />
  135. <SubMenu key="4-2" title={<span>下级菜单</span>}>
  136. <MenuItem key="4-2-1">菜单</MenuItem>
  137. <SubMenu title={<span>下下级菜单</span>} key="4-2-2">
  138. <MenuItem key="4-2-2-1">菜单</MenuItem>
  139. <MenuItem key="4-2-2-2">菜单2</MenuItem>
  140. </SubMenu>
  141. </SubMenu>
  142. </SubMenu>
  143. <MenuItem disabled>禁用效果</MenuItem>
  144. <MenuItem key="4-3">普通菜单</MenuItem>
  145. </StyledMenu>
  146. </div>
  147. );
  148. }
  149. }
  150. ReactDOM.render(<Sider />, mountNode);

切换菜单类型

展示动态切换模式。

StyledMenu ICE 风格导航 - 图6

查看源码在线预览

import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import { Icon, Switch } from '@icedesign/base';
import StyledMenu, {
  Item as MenuItem,
  SubMenu,
  ItemGroup as MenuItemGroup
} from '@icedesign/styled-menu';

class Sider extends Component {
  state = {
    mode: 'inline'
  };
  changeMode = value => {
    this.setState({
      mode: value ? 'vertical' : 'inline'
    });
  };
  render() {
    return (
      <div>
        <Switch onChange={this.changeMode} />
        <br />
        <br />
        <StyledMenu
          style={{ width: 240 }}
          defaultOpenKeys={['sub1']}
          mode={this.state.mode}
        >
          <SubMenu
            key="sub1"
            title={
              <span>
                <Icon type="filter" />
                <span>Navigation One</span>
              </span>
            }
          >
            <MenuItemGroup title="Item 1">
              <MenuItem key="1">Option 1</MenuItem>
              <MenuItem key="2">Option 2</MenuItem>
            </MenuItemGroup>
            <MenuItemGroup title="Item 2">
              <MenuItem key="3">Option 3</MenuItem>
              <MenuItem key="4">Option 4</MenuItem>
            </MenuItemGroup>
          </SubMenu>
          <SubMenu
            key="sub2"
            title={
              <span>
                <Icon type="pin" />
                <span>Navigation Two</span>
              </span>
            }
          >
            <MenuItem key="5">Option 5</MenuItem>
            <MenuItem key="6">Option 6</MenuItem>
            <SubMenu key="sub3" title="SubMenu">
              <MenuItem key="7">Option 7</MenuItem>
              <MenuItem key="8">Option 8</MenuItem>
            </SubMenu>
          </SubMenu>
          <SubMenu
            key="sub4"
            title={
              <span>
                <Icon type="history" />
                <span>Navigation Three</span>
              </span>
            }
          >
            <MenuItem key="9">Option 9</MenuItem>
            <MenuItem key="10">Option 10</MenuItem>
            <MenuItem key="11">Option 11</MenuItem>
            <MenuItem key="12">Option 12</MenuItem>
          </SubMenu>
        </StyledMenu>
      </div>
    );
  }
}

ReactDOM.render(<Sider />, mountNode);

收缩模式

演示收缩模式效果。

每个 MenuItem 中要收缩的元素,必须附带 ice-menu-collapse-hide 这个 className,并且对外框做一些宽度样式调整。

StyledMenu ICE 风格导航 - 图7

查看源码在线预览

import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import { Icon, Button } from '@icedesign/base';
import StyledMenu, {
  Item as MenuItem,
  SubMenu,
  ItemGroup as MenuItemGroup
} from '@icedesign/styled-menu';

class Sider extends Component {
  constructor(props) {
    super(props);

    this.state = {
      collapse: true,
      currentSelectedKey: ''
    };
  }

  toggleCollapse = () => {
    this.setState({
      collapse: !this.state.collapse
    });
  };

  handleSelect = info => {
    console.log(info);
    this.setState({
      currentSelectedKey: info.key
    });
  };

  render() {
    return (
      <div>
        <Button
          style={{ width: 60, marginBottom: 10 }}
          onClick={this.toggleCollapse}
        >
          <Icon type={this.state.collapse ? 'arrow-right' : 'arrow-left'} />
        </Button>
        <StyledMenu
          style={{ width: this.state.collapse ? 60 : 240 }}
          // defaultOpenKeys={['sub1']}
          inlineCollapsed={this.state.collapse}
          theme="dark"
          mode="inline"
          onSelect={this.handleSelect}
          selectedKeys={[this.state.currentSelectedKey]}
        >
          <StyledMenu.Item key="1">
            <Icon type="cart" />
            <span className="ice-menu-collapse-hide">Option 1</span>
          </StyledMenu.Item>
          <StyledMenu.Item key="2">
            <Icon type="help" />
            <span className="ice-menu-collapse-hide">Option 2</span>
          </StyledMenu.Item>
          <StyledMenu.Item key="3">
            <Icon type="box" />
            <span className="ice-menu-collapse-hide">Option 3</span>
          </StyledMenu.Item>
          <SubMenu
            key="sub1"
            title={
              <span>
                <Icon type="table" />
                <span className="ice-menu-collapse-hide">Navigation One</span>
              </span>
            }
          >
            <StyledMenu.Item key="5">Option 5</StyledMenu.Item>
            <StyledMenu.Item key="6">Option 6</StyledMenu.Item>
            <StyledMenu.Item key="7">Option 7</StyledMenu.Item>
            <StyledMenu.Item key="8">Option 8</StyledMenu.Item>
          </SubMenu>
          <SubMenu
            key="sub2"
            title={
              <span>
                <Icon type="compass" />
                <span className="ice-menu-collapse-hide">Navigation Two</span>
              </span>
            }
          >
            <StyledMenu.Item key="9">Option 9</StyledMenu.Item>
            <StyledMenu.Item key="10">Option 10</StyledMenu.Item>
            <SubMenu key="sub3" title="SubMenu">
              <StyledMenu.Item key="11">Option 11</StyledMenu.Item>
              <StyledMenu.Item key="12">Option 12</StyledMenu.Item>
            </SubMenu>
          </SubMenu>
        </StyledMenu>
      </div>
    );
  }
}

ReactDOM.render(<Sider />, mountNode);

相关区块

StyledMenu ICE 风格导航 - 图8

暂无相关区块