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 支持两种主题:lightdark

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 #

属性 说明 类型 默认值
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