Menu 菜单

在一个临时的面板上显示一组操作。

规则

  • 至少包含 2 个以上的菜单项。

  • 不应该被当做主要导航方式。

代码演示

菜单

  1. /* eslint global-require:0, no-nested-ternary:0 */
  2. import { Menu, ActivityIndicator, NavBar } from 'antd-mobile';
  3. const data = [
  4. {
  5. value: '1',
  6. label: 'Food',
  7. children: [
  8. {
  9. label: 'American Foods',
  10. value: '1',
  11. disabled: false,
  12. },
  13. {
  14. label: 'Chinese Food',
  15. value: '2',
  16. }, {
  17. label: 'Hot Pot',
  18. value: '3',
  19. }, {
  20. label: 'Buffet',
  21. value: '4',
  22. }, {
  23. label: 'Fast Food',
  24. value: '5',
  25. }, {
  26. label: 'Snack',
  27. value: '6',
  28. }, {
  29. label: 'Bread',
  30. value: '7',
  31. }, {
  32. label: 'Fruit',
  33. value: '8',
  34. }, {
  35. label: 'Noodle',
  36. value: '9',
  37. }, {
  38. label: 'Leisure Food',
  39. value: '10',
  40. }],
  41. }, {
  42. value: '2',
  43. label: 'Supermarket',
  44. children: [
  45. {
  46. label: 'All Supermarkets',
  47. value: '1',
  48. }, {
  49. label: 'Supermarket',
  50. value: '2',
  51. disabled: true,
  52. }, {
  53. label: 'C-Store',
  54. value: '3',
  55. }, {
  56. label: 'Personal Care',
  57. value: '4',
  58. }],
  59. },
  60. {
  61. value: '3',
  62. label: 'Extra',
  63. isLeaf: true,
  64. children: [
  65. {
  66. label: 'you can not see',
  67. value: '1',
  68. },
  69. ],
  70. },
  71. ];
  72. class MenuExample extends React.Component {
  73. constructor(...args) {
  74. super(...args);
  75. this.state = {
  76. initData: '',
  77. show: false,
  78. };
  79. }
  80. onChange = (value) => {
  81. let label = '';
  82. data.forEach((dataItem) => {
  83. if (dataItem.value === value[0]) {
  84. label = dataItem.label;
  85. if (dataItem.children && value[1]) {
  86. dataItem.children.forEach((cItem) => {
  87. if (cItem.value === value[1]) {
  88. label += ` ${cItem.label}`;
  89. }
  90. });
  91. }
  92. }
  93. });
  94. console.log(label);
  95. }
  96. handleClick = (e) => {
  97. e.preventDefault(); // Fix event propagation on Android
  98. this.setState({
  99. show: !this.state.show,
  100. });
  101. // mock for async data loading
  102. if (!this.state.initData) {
  103. setTimeout(() => {
  104. this.setState({
  105. initData: data,
  106. });
  107. }, 500);
  108. }
  109. }
  110. render() {
  111. const { initData, show } = this.state;
  112. const menuEl = (
  113. <Menu
  114. className="foo-menu"
  115. data={initData}
  116. value={['1', '3']}
  117. onChange={this.onChange}
  118. height={document.documentElement.clientHeight * 0.6}
  119. />
  120. );
  121. const loadingEl = (
  122. <div style={{ position: 'absolute', width: '100%', height: document.documentElement.clientHeight * 0.6, display: 'flex', justifyContent: 'center' }}>
  123. <ActivityIndicator size="large" />
  124. </div>
  125. );
  126. return (
  127. <div className={show ? 'menu-active' : ''}>
  128. <div>
  129. <NavBar
  130. leftContent="Menu"
  131. mode="light"
  132. iconName={require('./menu.svg')}
  133. onLeftClick={this.handleClick}
  134. className="top-nav-bar"
  135. >
  136. Basic menu
  137. </NavBar>
  138. </div>
  139. {show ? initData ? menuEl : loadingEl : null}
  140. </div>
  141. );
  142. }
  143. }
  144. ReactDOM.render(<MenuExample />, mountNode);
  1. .foo-menu {
  2. position: absolute;
  3. z-index: 100 !important;
  4. width: 100%;
  5. }
  6. .top-nav-bar {
  7. position: relative;
  8. z-index: 100 !important;
  9. background-color: #008AE6;
  10. color: #FFF;
  11. }
  12. .am-navbar-title {
  13. color: #FFF!important;
  14. }
  15. .menu-active:after {
  16. content: ' ';
  17. position: absolute;
  18. top: 0;
  19. width: 100%;
  20. height: 100%;
  21. background-color: #000;
  22. opacity: 0.4;
  23. z-index: 99;
  24. }

单级菜单

  1. /* eslint global-require:0, no-nested-ternary:0 */
  2. import { Menu, ActivityIndicator, NavBar } from 'antd-mobile';
  3. const data = [
  4. {
  5. value: '1',
  6. label: 'Food',
  7. }, {
  8. value: '2',
  9. label: 'Supermarket',
  10. },
  11. {
  12. value: '3',
  13. label: 'Extra',
  14. isLeaf: true,
  15. },
  16. ];
  17. class MenuExample extends React.Component {
  18. constructor(...args) {
  19. super(...args);
  20. this.state = {
  21. initData: '',
  22. show: false,
  23. };
  24. }
  25. onChange = (value) => {
  26. let label = '';
  27. data.forEach((dataItem) => {
  28. if (dataItem.value === value[0]) {
  29. label = dataItem.label;
  30. if (dataItem.children && value[1]) {
  31. dataItem.children.forEach((cItem) => {
  32. if (cItem.value === value[1]) {
  33. label += ` ${cItem.label}`;
  34. }
  35. });
  36. }
  37. }
  38. });
  39. console.log(label);
  40. }
  41. handleClick = (e) => {
  42. e.preventDefault(); // Fix event propagation on Android
  43. this.setState({
  44. show: !this.state.show,
  45. });
  46. // mock for async data loading
  47. if (!this.state.initData) {
  48. setTimeout(() => {
  49. this.setState({
  50. initData: data,
  51. });
  52. }, 500);
  53. }
  54. }
  55. render() {
  56. const { initData, show } = this.state;
  57. const menuEl = (
  58. <Menu
  59. className="single-foo-menu"
  60. data={initData}
  61. value={['1']}
  62. level={1}
  63. onChange={this.onChange}
  64. height={document.documentElement.clientHeight * 0.6}
  65. />
  66. );
  67. const loadingEl = (
  68. <div style={{ position: 'absolute', width: '100%', height: document.documentElement.clientHeight * 0.6, display: 'flex', justifyContent: 'center' }}>
  69. <ActivityIndicator size="large" />
  70. </div>
  71. );
  72. return (
  73. <div className={show ? 'single-menu-active' : ''}>
  74. <div>
  75. <NavBar
  76. leftContent="Menu"
  77. mode="light"
  78. iconName={require('./menu.svg')}
  79. onLeftClick={this.handleClick}
  80. className="single-top-nav-bar"
  81. >
  82. OneLevel menu
  83. </NavBar>
  84. </div>
  85. {show ? initData ? menuEl : loadingEl : null}
  86. </div>
  87. );
  88. }
  89. }
  90. ReactDOM.render(<MenuExample />, mountNode);
  1. .single-foo-menu {
  2. position: absolute;
  3. z-index: 90 !important;
  4. width: 100%;
  5. }
  6. .single-top-nav-bar {
  7. position: relative;
  8. z-index: 90 !important;
  9. background-color: #008AE6;
  10. color: #FFF;
  11. }
  12. .am-navbar-title {
  13. color: #FFF!important;
  14. }
  15. .single-menu-active:after {
  16. content: ' ';
  17. position: absolute;
  18. top: 0;
  19. width: 100%;
  20. height: 100%;
  21. background-color: #000;
  22. opacity: 0.4;
  23. z-index: 89;
  24. }

菜单多选

  1. /* eslint global-require:0, no-nested-ternary:0 */
  2. import { Menu, ActivityIndicator, NavBar } from 'antd-mobile';
  3. const data = [
  4. {
  5. value: '1',
  6. label: 'Food',
  7. children: [
  8. {
  9. label: 'American Foods',
  10. value: '1',
  11. disabled: false,
  12. },
  13. {
  14. label: 'Chinese Food',
  15. value: '2',
  16. }, {
  17. label: 'Hot Pot',
  18. value: '3',
  19. }, {
  20. label: 'Buffet',
  21. value: '4',
  22. }, {
  23. label: 'Fast Food',
  24. value: '5',
  25. }, {
  26. label: 'Snack',
  27. value: '6',
  28. }, {
  29. label: 'Bread',
  30. value: '7',
  31. }, {
  32. label: 'Fruit',
  33. value: '8',
  34. }, {
  35. label: 'Noodle',
  36. value: '9',
  37. }, {
  38. label: 'Leisure Food',
  39. value: '10',
  40. }],
  41. }, {
  42. value: '2',
  43. label: 'Supermarket',
  44. children: [
  45. {
  46. label: 'All Supermarkets',
  47. value: '1',
  48. }, {
  49. label: 'Supermarket',
  50. value: '2',
  51. disabled: true,
  52. }, {
  53. label: 'C-Store',
  54. value: '3',
  55. }, {
  56. label: 'Personal Care',
  57. value: '4',
  58. }],
  59. },
  60. {
  61. value: '3',
  62. label: 'Extra',
  63. isLeaf: true,
  64. children: [
  65. {
  66. label: 'you can not see',
  67. value: '1',
  68. },
  69. ],
  70. },
  71. ];
  72. class MultiMenuExample extends React.Component {
  73. constructor(...args) {
  74. super(...args);
  75. this.state = {
  76. initData: '',
  77. show: false,
  78. };
  79. }
  80. onChange = (value) => {
  81. console.log(value);
  82. }
  83. onOk = (value) => {
  84. console.log(value);
  85. this.onCancel();
  86. }
  87. onCancel = () => {
  88. this.setState({ show: false });
  89. }
  90. handleClick = (e) => {
  91. e.preventDefault(); // Fix event propagation on Android
  92. this.setState({
  93. show: !this.state.show,
  94. });
  95. // mock for async data loading
  96. if (!this.state.initData) {
  97. setTimeout(() => {
  98. this.setState({
  99. initData: data,
  100. });
  101. }, 500);
  102. }
  103. }
  104. render() {
  105. const { initData, show } = this.state;
  106. const menuEl = (
  107. <Menu
  108. className="multi-foo-menu"
  109. data={initData}
  110. value={['1', ['3', '4']]}
  111. onChange={this.onChange}
  112. onOk={this.onOk}
  113. onCancel={this.onCancel}
  114. height={document.documentElement.clientHeight * 0.6}
  115. multiSelect
  116. />
  117. );
  118. const loadingEl = (
  119. <div style={{ position: 'absolute', width: '100%', height: document.documentElement.clientHeight * 0.6, display: 'flex', justifyContent: 'center' }}>
  120. <ActivityIndicator size="large" />
  121. </div>
  122. );
  123. return (
  124. <div className={show ? 'multi-menu-active' : ''}>
  125. <div>
  126. <NavBar
  127. leftContent="Menu"
  128. mode="light"
  129. iconName={require('./menu.svg')}
  130. onLeftClick={this.handleClick}
  131. className="multi-top-nav-bar"
  132. >
  133. Multi select menu
  134. </NavBar>
  135. </div>
  136. {show ? initData ? menuEl : loadingEl : null}
  137. </div>
  138. );
  139. }
  140. }
  141. ReactDOM.render(<MultiMenuExample />, mountNode);
  1. .multi-foo-menu {
  2. position: absolute;
  3. z-index: 80 !important;
  4. width: 100%;
  5. }
  6. .multi-top-nav-bar {
  7. position: relative;
  8. z-index: 80 !important;
  9. background-color: #008AE6;
  10. color: #FFF;
  11. }
  12. .am-navbar-title {
  13. color: #FFF!important;
  14. }
  15. .multi-menu-active:after {
  16. content: ' ';
  17. position: absolute;
  18. top: 0;
  19. width: 100%;
  20. height: 100%;
  21. background-color: #000;
  22. opacity: 0.4;
  23. z-index: 79;
  24. }

单级菜单多选

  1. /* eslint global-require:0, no-nested-ternary:0 */
  2. import { Menu, ActivityIndicator, NavBar } from 'antd-mobile';
  3. const data = [
  4. {
  5. value: '1',
  6. label: 'Food',
  7. }, {
  8. value: '2',
  9. label: 'Supermarket',
  10. },
  11. {
  12. value: '3',
  13. label: 'Extra',
  14. isLeaf: true,
  15. },
  16. ];
  17. class MultiMenuExample extends React.Component {
  18. constructor(...args) {
  19. super(...args);
  20. this.state = {
  21. initData: '',
  22. show: false,
  23. };
  24. }
  25. onChange = (value) => {
  26. console.log(value);
  27. }
  28. onOk = (value) => {
  29. console.log(value);
  30. this.onCancel();
  31. }
  32. onCancel = () => {
  33. this.setState({ show: false });
  34. }
  35. handleClick = (e) => {
  36. e.preventDefault(); // Fix event propagation on Android
  37. this.setState({
  38. show: !this.state.show,
  39. });
  40. // mock for async data loading
  41. if (!this.state.initData) {
  42. setTimeout(() => {
  43. this.setState({
  44. initData: data,
  45. });
  46. }, 500);
  47. }
  48. }
  49. render() {
  50. const { initData, show } = this.state;
  51. const menuEl = (
  52. <Menu
  53. className="single-multi-foo-menu"
  54. data={initData}
  55. value={['1']}
  56. level={1}
  57. onChange={this.onChange}
  58. onOk={this.onOk}
  59. onCancel={this.onCancel}
  60. height={document.documentElement.clientHeight * 0.6}
  61. multiSelect
  62. />
  63. );
  64. const loadingEl = (
  65. <div style={{ position: 'absolute', width: '100%', height: document.documentElement.clientHeight * 0.6, display: 'flex', justifyContent: 'center' }}>
  66. <ActivityIndicator size="large" />
  67. </div>
  68. );
  69. return (
  70. <div className={show ? 'single-multi-menu-active' : ''}>
  71. <div>
  72. <NavBar
  73. leftContent="Menu"
  74. mode="light"
  75. iconName={require('./menu.svg')}
  76. onLeftClick={this.handleClick}
  77. className="single-multi-top-nav-bar"
  78. >
  79. Single Multi menu
  80. </NavBar>
  81. </div>
  82. {show ? initData ? menuEl : loadingEl : null}
  83. </div>
  84. );
  85. }
  86. }
  87. ReactDOM.render(<MultiMenuExample />, mountNode);
  1. .single-multi-foo-menu {
  2. position: absolute;
  3. z-index: 70 !important;
  4. width: 100%;
  5. }
  6. .single-multi-top-nav-bar {
  7. position: relative;
  8. z-index: 70 !important;
  9. background-color: #008AE6;
  10. color: #FFF;
  11. }
  12. .am-navbar-title {
  13. color: #FFF!important;
  14. }
  15. .single-multi-menu-active:after {
  16. content: ' ';
  17. position: absolute;
  18. top: 0;
  19. width: 100%;
  20. height: 100%;
  21. background-color: #000;
  22. opacity: 0.4;
  23. z-index: 69;
  24. }

Menu菜单 - 图1

API

适用平台:WEB
属性说明类型默认值
data数据(isLeaf 设置后 children 无效)Array<{label, value, disabled?, children<data>?, isLeaf?}>[]
level菜单级数,可选1/2number2
value初始值,一级和二级筛选数据的value组成的数组。在多选状态下,如果为二级菜单,则数组的第一个元素为一级菜单的选项,数组的第二个元素是一个数组,里面包含了二级菜单的多选项;如果为一级菜单,则数组所有元素都是多选项Array
onChange选择后的回调函数(item: Object): void
onOk多选状态下确认按钮回调(value: Object): void
onCancel多选状态下取消按钮回调(): void
height筛选组件的高度numberdocument.documentElement.clientHeight / 2
multiSelect是否支持菜单多选booleanfalse