Menu 导航菜单 #
概述 #
Menu 导航菜单是页面导航的核心组件,支持水平导航、垂直导航、内嵌导航等多种模式。
基础用法 #
顶部导航 #
tsx
import { Menu } from 'antd';
import { MailOutlined, AppstoreOutlined, SettingOutlined } from '@ant-design/icons';
const items = [
{ key: 'mail', label: '邮件', icon: <MailOutlined /> },
{ key: 'app', label: '应用', icon: <AppstoreOutlined /> },
{ key: 'setting', label: '设置', icon: <SettingOutlined /> },
];
<Menu mode="horizontal" items={items} />
垂直导航 #
tsx
import { Menu } from 'antd';
import { MailOutlined, AppstoreOutlined, SettingOutlined } from '@ant-design/icons';
const items = [
{ key: 'mail', label: '邮件', icon: <MailOutlined /> },
{ key: 'app', label: '应用', icon: <AppstoreOutlined /> },
{ key: 'setting', label: '设置', icon: <SettingOutlined /> },
];
<Menu mode="vertical" items={items} />
内嵌导航 #
tsx
import { Menu } from 'antd';
import { MailOutlined, AppstoreOutlined, SettingOutlined } from '@ant-design/icons';
const items = [
{
key: 'sub1',
label: '导航一',
icon: <MailOutlined />,
children: [
{ key: '1', label: '选项1' },
{ key: '2', label: '选项2' },
{ key: '3', label: '选项3' },
],
},
{
key: 'sub2',
label: '导航二',
icon: <AppstoreOutlined />,
children: [
{ key: '4', label: '选项4' },
{ key: '5', label: '选项5' },
],
},
];
<Menu mode="inline" items={items} defaultOpenKeys={['sub1']} />
主题 #
Menu 支持两种主题:light 和 dark。
tsx
import { Menu } from 'antd';
<Menu theme="dark" mode="horizontal" items={items} />
<Menu theme="light" mode="horizontal" items={items} />
子菜单 #
展开子菜单 #
tsx
import { Menu } from 'antd';
import { MailOutlined, SettingOutlined } from '@ant-design/icons';
const items = [
{
key: 'sub1',
label: '导航一',
icon: <MailOutlined />,
children: [
{ key: '1', label: '选项1' },
{ key: '2', label: '选项2' },
{
key: 'sub1-2',
label: '子菜单',
children: [
{ key: '3', label: '选项3' },
{ key: '4', label: '选项4' },
],
},
],
},
{
key: 'sub2',
label: '导航二',
icon: <SettingOutlined />,
children: [
{ key: '5', label: '选项5' },
{ key: '6', label: '选项6' },
],
},
];
<Menu mode="inline" items={items} defaultOpenKeys={['sub1']} />
默认展开 #
tsx
import { Menu } from 'antd';
<Menu
mode="inline"
items={items}
defaultOpenKeys={['sub1', 'sub2']}
defaultSelectedKeys={['1']}
/>
受控菜单 #
tsx
import { Menu } from 'antd';
import { useState } from 'react';
const [current, setCurrent] = useState('mail');
const onClick = (e) => {
setCurrent(e.key);
};
<Menu
onClick={onClick}
selectedKeys={[current]}
mode="horizontal"
items={items}
/>
只展开一个子菜单 #
tsx
import { Menu } from 'antd';
<Menu
mode="inline"
openKeys={openKeys}
onOpenChange={(keys) => {
const latestOpenKey = keys.find(key => openKeys.indexOf(key) === -1);
setOpenKeys(latestOpenKey ? [latestOpenKey] : []);
}}
items={items}
/>
切换菜单类型 #
tsx
import { Menu, Button, Radio } from 'antd';
import { useState } from 'react';
const [mode, setMode] = useState('inline');
const [theme, setTheme] = useState('light');
<>
<Radio.Group onChange={(e) => setMode(e.target.value)} value={mode}>
<Radio value="horizontal">水平</Radio>
<Radio value="vertical">垂直</Radio>
<Radio value="inline">内嵌</Radio>
</Radio.Group>
<Radio.Group onChange={(e) => setTheme(e.target.value)} value={theme}>
<Radio value="light">亮色</Radio>
<Radio value="dark">暗色</Radio>
</Radio.Group>
<br />
<br />
<Menu
style={{ width: 256 }}
mode={mode}
theme={theme}
items={items}
/>
</>
菜单项分组 #
tsx
import { Menu } from 'antd';
const items = [
{
type: 'group',
label: '分组一',
children: [
{ key: '1', label: '选项1' },
{ key: '2', label: '选项2' },
],
},
{
type: 'group',
label: '分组二',
children: [
{ key: '3', label: '选项3' },
{ key: '4', label: '选项4' },
],
},
];
<Menu mode="vertical" items={items} />
菜单项类型 #
禁用菜单项 #
tsx
import { Menu } from 'antd';
const items = [
{ key: '1', label: '正常菜单项' },
{ key: '2', label: '禁用菜单项', disabled: true },
{ key: '3', label: '正常菜单项' },
];
<Menu items={items} />
危险菜单项 #
tsx
import { Menu } from 'antd';
const items = [
{ key: '1', label: '正常菜单项' },
{ key: '2', label: '危险操作', danger: true },
];
<Menu items={items} />
分割线 #
tsx
import { Menu } from 'antd';
const items = [
{ key: '1', label: '选项1' },
{ type: 'divider' },
{ key: '2', label: '选项2' },
];
<Menu items={items} />
API #
Menu #
| 属性 | 说明 | 类型 | 默认值 |
|---|---|---|---|
| defaultOpenKeys | 默认展开的子菜单 | string[] | - |
| defaultSelectedKeys | 默认选中的菜单项 | string[] | - |
| expandIcon | 展开图标 | ReactNode | (props) => ReactNode | - |
| forceSubMenuRender | 强制渲染子菜单 | boolean | false |
| inlineCollapsed | 内嵌模式折叠状态 | boolean | - |
| inlineIndent | 内嵌模式缩进 | number | 24 |
| items | 菜单内容 | ItemType[] | - |
| mode | 菜单类型 | horizontal | vertical | inline |
vertical |
| multiple | 是否允许多选 | boolean | false |
| openKeys | 展开的子菜单 | string[] | - |
| selectable | 是否允许选中 | boolean | true |
| selectedKeys | 选中的菜单项 | string[] | - |
| style | 样式 | CSSProperties | - |
| subMenuCloseDelay | 子菜单关闭延迟 | number | 0.1 |
| subMenuOpenDelay | 子菜单展开延迟 | number | 0 |
| theme | 主题 | light | dark |
light |
| triggerSubMenuAction | 子菜单触发方式 | hover | click |
hover |
| onClick | 点击菜单项回调 | ({ key, keyPath, domEvent }) => void | - |
| onDeselect | 取消选中回调 | ({ key, keyPath, selectedKeys, domEvent }) => void | - |
| onOpenChange | SubMenu 展开回调 | (openKeys) => void | - |
| onSelect | 选中菜单项回调 | ({ key, keyPath, selectedKeys, domEvent }) => void | - |
ItemType #
| 属性 | 说明 | 类型 | 默认值 |
|---|---|---|---|
| danger | 危险样式 | boolean | false |
| disabled | 是否禁用 | boolean | false |
| icon | 图标 | ReactNode | - |
| key | 唯一标识 | string | - |
| label | 菜单项标题 | ReactNode | - |
| title | 悬浮提示 | string | false |
| type | 菜单类型 | item | group | divider |
item |
| children | 子菜单 | ItemType[] | - |
最佳实践 #
1. 配合 Layout 使用 #
tsx
import { Layout, Menu } from 'antd';
const { Sider, Header, Content } = Layout;
<Layout>
<Header>
<Menu theme="dark" mode="horizontal" items={headerItems} />
</Header>
<Layout>
<Sider>
<Menu mode="inline" items={sideItems} />
</Sider>
<Content>内容</Content>
</Layout>
</Layout>
2. 配合路由使用 #
tsx
import { Menu } from 'antd';
import { useNavigate, useLocation } from 'react-router-dom';
const MenuWithRouter = () => {
const navigate = useNavigate();
const location = useLocation();
const items = [
{ key: '/home', label: '首页' },
{ key: '/about', label: '关于' },
{ key: '/contact', label: '联系' },
];
return (
<Menu
mode="horizontal"
selectedKeys={[location.pathname]}
onClick={({ key }) => navigate(key)}
items={items}
/>
);
};
3. 动态菜单 #
tsx
import { Menu } from 'antd';
import { useState, useEffect } from 'react';
const DynamicMenu = () => {
const [items, setItems] = useState([]);
useEffect(() => {
fetchMenuItems().then(data => setItems(data));
}, []);
return <Menu items={items} />;
};
下一步 #
接下来学习 Breadcrumb 面包屑 组件!
最后更新:2026-03-28