Menu 菜单
在一个临时的面板上显示一组操作。规则
至少包含 2 个以上的菜单项。
不应该被当做主要导航方式。
代码演示
/* eslint no-nested-ternary:0 */
import { Menu, ActivityIndicator, NavBar } from 'antd-mobile';
const data = [
{
value: '1',
label: 'Food',
children: [
{
label: 'All Foods',
value: '1',
disabled: false,
},
{
label: 'Chinese Food',
value: '2',
}, {
label: 'Hot Pot',
value: '3',
}, {
label: 'Buffet',
value: '4',
}, {
label: 'Fast Food',
value: '5',
}, {
label: 'Snack',
value: '6',
}, {
label: 'Bread',
value: '7',
}, {
label: 'Fruit',
value: '8',
}, {
label: 'Noodle',
value: '9',
}, {
label: 'Leisure Food',
value: '10',
}],
}, {
value: '2',
label: 'Supermarket',
children: [
{
label: 'All Supermarkets',
value: '1',
}, {
label: 'Supermarket',
value: '2',
disabled: true,
}, {
label: 'C-Store',
value: '3',
}, {
label: 'Personal Care',
value: '4',
}],
},
{
value: '3',
label: 'Extra',
isLeaf: true,
children: [
{
label: 'you can not see',
value: '1',
},
],
},
];
class MenuExample extends React.Component {
constructor(...args) {
super(...args);
this.state = {
initData: '',
show: false,
};
}
onChange = (value) => {
let label = '';
data.forEach((dataItem) => {
if (dataItem.value === value[0]) {
label = dataItem.label;
if (dataItem.children && value[1]) {
dataItem.children.forEach((cItem) => {
if (cItem.value === value[1]) {
label += ` ${cItem.label}`;
}
});
}
}
});
console.log(label);
}
handleClick = (e) => {
e.preventDefault(); // Fix event propagation on Android
this.setState({
show: !this.state.show,
});
// mock for async data loading
if (!this.state.initData) {
setTimeout(() => {
this.setState({
initData: data,
});
}, 500);
}
}
onMaskClick = () => {
this.setState({
show: false,
});
}
render() {
const { initData, show } = this.state;
const menuEl = (
<Menu
className="foo-menu"
data={initData}
value={['1', '3']}
onChange={this.onChange}
height={document.documentElement.clientHeight * 0.6}
/>
);
const loadingEl = (
<div style={{ width: '100%', height: document.documentElement.clientHeight * 0.6, display: 'flex', justifyContent: 'center' }}>
<ActivityIndicator size="large" />
</div>
);
return (
<div className={show ? 'menu-active' : ''}>
<div>
<NavBar
leftContent="Menu"
mode="light"
icon={<img src="https://gw.alipayobjects.com/zos/rmsportal/iXVHARNNlmdCGnwWxQPH.svg" className="am-icon am-icon-md" alt="" />}
onLeftClick={this.handleClick}
className="top-nav-bar"
>
Here is title
</NavBar>
</div>
{show ? initData ? menuEl : loadingEl : null}
{show ? <div className="menu-mask" onClick={this.onMaskClick} /> : null}
</div>
);
}
}
ReactDOM.render(<MenuExample />, mountNode);
.foo-menu {
position: relative;
z-index: 1000 !important;
}
.menu-active .top-nav-bar{
z-index: 80;
}
.top-nav-bar {
position: relative;
background-color: #008AE6;
color: #FFF;
}
.am-navbar-title {
color: #FFF!important;
}
.menu-mask {
content: ' ';
position: absolute;
top: 0;
width: 100%;
height: 100%;
background-color: #000;
opacity: 0.4;
z-index: 79;
}
/* eslint global-require:0, no-nested-ternary:0 */
import { Menu, ActivityIndicator, NavBar } from 'antd-mobile';
const data = [
{
value: '1',
label: 'Food',
}, {
value: '2',
label: 'Supermarket',
},
{
value: '3',
label: 'Extra',
isLeaf: true,
},
];
class MenuExample extends React.Component {
constructor(...args) {
super(...args);
this.state = {
initData: '',
show: false,
};
}
onChange = (value) => {
let label = '';
data.forEach((dataItem) => {
if (dataItem.value === value[0]) {
label = dataItem.label;
if (dataItem.children && value[1]) {
dataItem.children.forEach((cItem) => {
if (cItem.value === value[1]) {
label += ` ${cItem.label}`;
}
});
}
}
});
console.log(label);
}
handleClick = (e) => {
e.preventDefault(); // Fix event propagation on Android
this.setState({
show: !this.state.show,
});
// mock for async data loading
if (!this.state.initData) {
setTimeout(() => {
this.setState({
initData: data,
});
}, 500);
}
}
onMaskClick = () => {
this.setState({
show: false,
});
}
render() {
const { initData, show } = this.state;
const menuEl = (
<Menu
className="single-foo-menu"
data={initData}
value={['1']}
level={1}
onChange={this.onChange}
height={document.documentElement.clientHeight * 0.6}
/>
);
const loadingEl = (
<div style={{ position: 'absolute', width: '100%', height: document.documentElement.clientHeight * 0.6, display: 'flex', justifyContent: 'center' }}>
<ActivityIndicator size="large" />
</div>
);
return (
<div className={show ? 'single-menu-active' : ''}>
<div>
<NavBar
leftContent="Menu"
mode="light"
onLeftClick={this.handleClick}
className="single-top-nav-bar"
>
OneLevel menu
</NavBar>
</div>
{show ? initData ? menuEl : loadingEl : null}
{show ? <div className="menu-mask" onClick={this.onMaskClick} /> : null}
</div>
);
}
}
ReactDOM.render(<MenuExample />, mountNode);
.single-foo-menu {
position: absolute;
z-index: 90 !important;
width: 100%;
}
.single-menu-active .single-top-nav-bar{
z-index: 90;
}
.single-top-nav-bar {
position: relative;
background-color: #008AE6;
color: #FFF;
}
.am-navbar-title {
color: #FFF!important;
}
.menu-mask {
position: absolute;
top: 0;
width: 100%;
height: 100%;
background-color: #000;
opacity: 0.4;
z-index: 89;
}
/* eslint global-require:0, no-nested-ternary:0 */
import { Menu, ActivityIndicator, NavBar } from 'antd-mobile';
const data = [
{
value: '1',
label: 'Food',
children: [
{
label: 'American Foods',
value: '1',
disabled: false,
},
{
label: 'Chinese Food',
value: '2',
}, {
label: 'Hot Pot',
value: '3',
}, {
label: 'Buffet',
value: '4',
}, {
label: 'Fast Food',
value: '5',
}, {
label: 'Snack',
value: '6',
}, {
label: 'Bread',
value: '7',
}, {
label: 'Fruit',
value: '8',
}, {
label: 'Noodle',
value: '9',
}, {
label: 'Leisure Food',
value: '10',
}],
}, {
value: '2',
label: 'Supermarket',
children: [
{
label: 'All Supermarkets',
value: '1',
}, {
label: 'Supermarket',
value: '2',
disabled: true,
}, {
label: 'C-Store',
value: '3',
}, {
label: 'Personal Care',
value: '4',
}],
},
{
value: '3',
label: 'Extra',
isLeaf: true,
children: [
{
label: 'you can not see',
value: '1',
},
],
},
];
class MultiMenuExample extends React.Component {
constructor(...args) {
super(...args);
this.state = {
initData: '',
show: false,
};
}
onChange = (value) => {
console.log(value);
}
onOk = (value) => {
console.log(value);
this.onCancel();
}
onCancel = () => {
this.setState({ show: false });
}
handleClick = (e) => {
e.preventDefault(); // Fix event propagation on Android
this.setState({
show: !this.state.show,
});
// mock for async data loading
if (!this.state.initData) {
setTimeout(() => {
this.setState({
initData: data,
});
}, 500);
}
}
onMaskClick = () => {
this.setState({
show: false,
});
}
render() {
const { initData, show } = this.state;
const menuEl = (
<Menu
className="multi-foo-menu"
data={initData}
value={['1', ['3', '4']]}
onChange={this.onChange}
onOk={this.onOk}
onCancel={this.onCancel}
height={document.documentElement.clientHeight * 0.6}
multiSelect
/>
);
const loadingEl = (
<div style={{ position: 'absolute', width: '100%', height: document.documentElement.clientHeight * 0.6, display: 'flex', justifyContent: 'center' }}>
<ActivityIndicator size="large" />
</div>
);
return (
<div className={show ? 'multi-menu-active' : ''}>
<div>
<NavBar
leftContent="Menu"
mode="light"
onLeftClick={this.handleClick}
className="multi-top-nav-bar"
>
Multi select menu
</NavBar>
</div>
{show ? initData ? menuEl : loadingEl : null}
{show ? <div className="menu-mask" onClick={this.onMaskClick} /> : null}
</div>
);
}
}
ReactDOM.render(<MultiMenuExample />, mountNode);
.multi-foo-menu {
position: absolute;
z-index: 80 !important;
width: 100%;
}
.multi-menu-active .multi-top-nav-bar{
z-index: 80;
}
.multi-top-nav-bar {
position: relative;
background-color: #008AE6;
color: #FFF;
}
.am-navbar-title {
color: #FFF!important;
}
.menu-mask {
content: ' ';
position: absolute;
top: 0;
width: 100%;
height: 100%;
background-color: #000;
opacity: 0.4;
z-index: 79;
}
/* eslint global-require:0, no-nested-ternary:0 */
import { Menu, ActivityIndicator, NavBar } from 'antd-mobile';
const data = [
{
value: '1',
label: 'Food',
}, {
value: '2',
label: 'Supermarket',
},
{
value: '3',
label: 'Extra',
isLeaf: true,
},
];
class MultiMenuExample extends React.Component {
constructor(...args) {
super(...args);
this.state = {
initData: '',
show: false,
};
}
onChange = (value) => {
console.log(value);
}
onOk = (value) => {
console.log(value);
this.onCancel();
}
onCancel = () => {
this.setState({ show: false });
}
handleClick = (e) => {
e.preventDefault(); // Fix event propagation on Android
this.setState({
show: !this.state.show,
});
// mock for async data loading
if (!this.state.initData) {
setTimeout(() => {
this.setState({
initData: data,
});
}, 500);
}
}
onMaskClick = () => {
this.setState({
show: false,
});
}
render() {
const { initData, show } = this.state;
const menuEl = (
<Menu
className="single-multi-foo-menu"
data={initData}
value={['1']}
level={1}
onChange={this.onChange}
onOk={this.onOk}
onCancel={this.onCancel}
height={document.documentElement.clientHeight * 0.6}
multiSelect
/>
);
const loadingEl = (
<div style={{ position: 'absolute', width: '100%', height: document.documentElement.clientHeight * 0.6, display: 'flex', justifyContent: 'center' }}>
<ActivityIndicator size="large" />
</div>
);
return (
<div className={show ? 'single-multi-menu-active' : ''}>
<div>
<NavBar
leftContent="Menu"
mode="light"
onLeftClick={this.handleClick}
className="single-multi-top-nav-bar"
>
Single Multi menu
</NavBar>
</div>
{show ? initData ? menuEl : loadingEl : null}
{show ? <div className="menu-mask" onClick={this.onMaskClick} /> : null}
</div>
);
}
}
ReactDOM.render(<MultiMenuExample />, mountNode);
.single-multi-foo-menu {
position: absolute;
z-index: 70 !important;
width: 100%;
}
.single-multi-menu-active .single-multi-top-nav-bar{
z-index: 80;
}
.single-multi-top-nav-bar {
position: relative;
background-color: #008AE6;
color: #FFF;
}
.am-navbar-title {
color: #FFF!important;
}
.menu-mask {
content: ' ';
position: absolute;
top: 0;
width: 100%;
height: 100%;
background-color: #000;
opacity: 0.4;
z-index: 69;
}
API
属性 | 说明 | 类型 | 默认值 |
---|---|---|---|
data | 数据(isLeaf 设置后 children 无效) | Array<{label: ReactNode, value, disabled?, children<data>?, isLeaf?}> | [] |
level | 菜单级数,可选1/2 | number | 2 |
value | 初始值,一级和二级筛选数据的value 组成的数组。在多选状态下,如果为二级菜单,则数组的第一个元素为一级菜单的选项,数组的第二个元素是一个数组,里面包含了二级菜单的多选项;如果为一级菜单,则数组所有元素都是多选项 | Array | |
onChange | 选择后的回调函数 | (item: Object): void | |
onOk | 多选状态下确认按钮回调 | (value: Object): void | |
onCancel | 多选状态下取消按钮回调 | (): void | |
height | 筛选组件的高度 | number | document.documentElement.clientHeight / 2 |
multiSelect | 是否支持菜单多选 | boolean | false |