Menu 导航菜单
为页面和功能提供导航的菜单列表。
何时使用
导航菜单是一个网站的灵魂,用户依赖导航在各个页面中进行跳转。一般分为顶部导航和侧边导航,顶部导航提供全局性的类目和功能,侧边导航提供多级结构来收纳和排列网站架构。
代码演示
顶部导航
水平的顶部导航菜单。
<template>
<div>
<a-menu v-model="current" mode="horizontal">
<a-menu-item key="mail"> <a-icon type="mail" />Navigation One </a-menu-item>
<a-menu-item key="app" disabled> <a-icon type="appstore" />Navigation Two </a-menu-item>
<a-sub-menu>
<span slot="title" class="submenu-title-wrapper"
><a-icon type="setting" />Navigation Three - Submenu</span
>
<a-menu-item-group title="Item 1">
<a-menu-item key="setting:1">
Option 1
</a-menu-item>
<a-menu-item key="setting:2">
Option 2
</a-menu-item>
</a-menu-item-group>
<a-menu-item-group title="Item 2">
<a-menu-item key="setting:3">
Option 3
</a-menu-item>
<a-menu-item key="setting:4">
Option 4
</a-menu-item>
</a-menu-item-group>
</a-sub-menu>
<a-menu-item key="alipay">
<a href="https://antdv.com" target="_blank" rel="noopener noreferrer"
>Navigation Four - Link</a
>
</a-menu-item>
</a-menu>
</div>
</template>
<script>
export default {
data() {
return {
current: ['mail'],
};
},
};
</script>
内嵌菜单
垂直菜单,子菜单内嵌在菜单区域。
<template>
<div>
<a-menu
style="width: 256px"
:default-selected-keys="['1']"
:open-keys.sync="openKeys"
mode="inline"
@click="handleClick"
>
<a-sub-menu key="sub1" @titleClick="titleClick">
<span slot="title"><a-icon type="mail" /><span>Navigation One</span></span>
<a-menu-item-group key="g1">
<template slot="title"> <a-icon type="qq" /><span>Item 1</span> </template>
<a-menu-item key="1">
Option 1
</a-menu-item>
<a-menu-item key="2">
Option 2
</a-menu-item>
</a-menu-item-group>
<a-menu-item-group key="g2" title="Item 2">
<a-menu-item key="3">
Option 3
</a-menu-item>
<a-menu-item key="4">
Option 4
</a-menu-item>
</a-menu-item-group>
</a-sub-menu>
<a-sub-menu key="sub2" @titleClick="titleClick">
<span slot="title"><a-icon type="appstore" /><span>Navigation Two</span></span>
<a-menu-item key="5">
Option 5
</a-menu-item>
<a-menu-item key="6">
Option 6
</a-menu-item>
<a-sub-menu key="sub3" title="Submenu">
<a-menu-item key="7">
Option 7
</a-menu-item>
<a-menu-item key="8">
Option 8
</a-menu-item>
</a-sub-menu>
</a-sub-menu>
<a-sub-menu key="sub4">
<span slot="title"><a-icon type="setting" /><span>Navigation Three</span></span>
<a-menu-item key="9">
Option 9
</a-menu-item>
<a-menu-item key="10">
Option 10
</a-menu-item>
<a-menu-item key="11">
Option 11
</a-menu-item>
<a-menu-item key="12">
Option 12
</a-menu-item>
</a-sub-menu>
</a-menu>
</div>
</template>
<script>
export default {
data() {
return {
current: ['mail'],
openKeys: ['sub1'],
};
},
watch: {
openKeys(val) {
console.log('openKeys', val);
},
},
methods: {
handleClick(e) {
console.log('click', e);
},
titleClick(e) {
console.log('titleClick', e);
},
},
};
</script>
缩起内嵌菜单
内嵌菜单可以被缩起/展开。
<template>
<div style="width: 256px">
<a-button type="primary" style="margin-bottom: 16px" @click="toggleCollapsed">
<a-icon :type="collapsed ? 'menu-unfold' : 'menu-fold'" />
</a-button>
<a-menu
:default-selected-keys="['1']"
:default-open-keys="['sub1']"
mode="inline"
theme="dark"
:inline-collapsed="collapsed"
>
<a-menu-item key="1">
<a-icon type="pie-chart" />
<span>Option 1</span>
</a-menu-item>
<a-menu-item key="2">
<a-icon type="desktop" />
<span>Option 2</span>
</a-menu-item>
<a-menu-item key="3">
<a-icon type="inbox" />
<span>Option 3</span>
</a-menu-item>
<a-sub-menu key="sub1">
<span slot="title"><a-icon type="mail" /><span>Navigation One</span></span>
<a-menu-item key="5">
Option 5
</a-menu-item>
<a-menu-item key="6">
Option 6
</a-menu-item>
<a-menu-item key="7">
Option 7
</a-menu-item>
<a-menu-item key="8">
Option 8
</a-menu-item>
</a-sub-menu>
<a-sub-menu key="sub2">
<span slot="title"><a-icon type="appstore" /><span>Navigation Two</span></span>
<a-menu-item key="9">
Option 9
</a-menu-item>
<a-menu-item key="10">
Option 10
</a-menu-item>
<a-sub-menu key="sub3" title="Submenu">
<a-menu-item key="11">
Option 11
</a-menu-item>
<a-menu-item key="12">
Option 12
</a-menu-item>
</a-sub-menu>
</a-sub-menu>
</a-menu>
</div>
</template>
<script>
export default {
data() {
return {
collapsed: false,
};
},
methods: {
toggleCollapsed() {
this.collapsed = !this.collapsed;
},
},
};
</script>
只展开当前父级菜单
点击菜单,收起其他展开的所有菜单,保持菜单聚焦简洁。
<template>
<div>
<a-menu mode="inline" :open-keys="openKeys" style="width: 256px" @openChange="onOpenChange">
<a-sub-menu key="sub1">
<span slot="title"><a-icon type="mail" /><span>Navigation One</span></span>
<a-menu-item key="1">
Option 1
</a-menu-item>
<a-menu-item key="2">
Option 2
</a-menu-item>
<a-menu-item key="3">
Option 3
</a-menu-item>
<a-menu-item key="4">
Option 4
</a-menu-item>
</a-sub-menu>
<a-sub-menu key="sub2">
<span slot="title"><a-icon type="appstore" /><span>Navigation Two</span></span>
<a-menu-item key="5">
Option 5
</a-menu-item>
<a-menu-item key="6">
Option 6
</a-menu-item>
<a-sub-menu key="sub3" title="Submenu">
<a-menu-item key="7">
Option 7
</a-menu-item>
<a-menu-item key="8">
Option 8
</a-menu-item>
</a-sub-menu>
</a-sub-menu>
<a-sub-menu key="sub4">
<span slot="title"><a-icon type="setting" /><span>Navigation Three</span></span>
<a-menu-item key="9">
Option 9
</a-menu-item>
<a-menu-item key="10">
Option 10
</a-menu-item>
<a-menu-item key="11">
Option 11
</a-menu-item>
<a-menu-item key="12">
Option 12
</a-menu-item>
</a-sub-menu>
</a-menu>
</div>
</template>
<script>
export default {
data() {
return {
rootSubmenuKeys: ['sub1', 'sub2', 'sub4'],
openKeys: ['sub1'],
};
},
methods: {
onOpenChange(openKeys) {
const latestOpenKey = openKeys.find(key => this.openKeys.indexOf(key) === -1);
if (this.rootSubmenuKeys.indexOf(latestOpenKey) === -1) {
this.openKeys = openKeys;
} else {
this.openKeys = latestOpenKey ? [latestOpenKey] : [];
}
},
},
};
</script>
垂直菜单
子菜单是弹出的形式。
<template>
<div>
<a-menu style="width: 256px" mode="vertical" @click="handleClick">
<a-menu-item key="1">
<a-icon type="mail" />
Navigation One
</a-menu-item>
<a-menu-item key="2">
<a-icon type="calendar" />
Navigation Two
</a-menu-item>
<a-sub-menu key="sub1">
<span slot="title"><a-icon type="appstore" /><span>Navigation Three</span></span>
<a-menu-item key="3">
Option 3
</a-menu-item>
<a-menu-item key="4">
Option 4
</a-menu-item>
<a-sub-menu key="sub1-2" title="Submenu">
<a-menu-item key="5">
Option 5
</a-menu-item>
<a-menu-item key="6">
Option 6
</a-menu-item>
</a-sub-menu>
</a-sub-menu>
<a-sub-menu key="sub2">
<span slot="title"><a-icon type="setting" /><span>Navigation Four</span></span>
<a-menu-item key="7">
Option 7
</a-menu-item>
<a-menu-item key="8">
Option 8
</a-menu-item>
<a-menu-item key="9">
Option 9
</a-menu-item>
<a-menu-item key="10">
Option 10
</a-menu-item>
</a-sub-menu>
</a-menu>
</div>
</template>
<script>
export default {
methods: {
handleClick(e) {
console.log('click ', e);
},
},
};
</script>
主题
内建了两套主题 light|dark
,默认 light
。
<template>
<div>
<a-switch
default-checked
checked-children="dark"
un-checked-children="light"
@change="changeTheme"
/>
<br />
<br />
<a-menu
style="width: 256px"
:default-selected-keys="['1']"
:default-open-keys="['sub1']"
mode="inline"
:theme="theme"
:selected-keys="[current]"
@click="handleClick"
>
<a-menu-item key="1">
<a-icon type="mail" />
Navigation One
</a-menu-item>
<a-menu-item key="2">
<a-icon type="calendar" />
Navigation Two
</a-menu-item>
<a-sub-menu key="sub1">
<span slot="title"><a-icon type="appstore" /><span>Navigation Three</span></span>
<a-menu-item key="3">
Option 3
</a-menu-item>
<a-menu-item key="4">
Option 4
</a-menu-item>
<a-sub-menu key="sub1-2" title="Submenu">
<a-menu-item key="5">
Option 5
</a-menu-item>
<a-menu-item key="6">
Option 6
</a-menu-item>
</a-sub-menu>
</a-sub-menu>
<a-sub-menu key="sub2">
<span slot="title"><a-icon type="setting" /><span>Navigation Four</span></span>
<a-menu-item key="7">
Option 7
</a-menu-item>
<a-menu-item key="8">
Option 8
</a-menu-item>
<a-menu-item key="9">
Option 9
</a-menu-item>
<a-menu-item key="10">
Option 10
</a-menu-item>
</a-sub-menu>
</a-menu>
</div>
</template>
<script>
export default {
data() {
return {
current: '1',
theme: 'dark',
};
},
methods: {
handleClick(e) {
console.log('click ', e);
this.current = e.key;
},
changeTheme(checked) {
this.theme = checked ? 'dark' : 'light';
},
},
};
</script>
切换菜单类型
展示动态切换模式。
<template>
<div>
<a-switch :default-checked="false" @change="changeMode" /> Change Mode
<span className="ant-divider" style="margin: 0 1em" />
<a-switch :default-checked="false" @change="changeTheme" /> Change Theme
<br />
<br />
<a-menu
style="width: 256px"
:default-selected-keys="['1']"
:default-open-keys="['sub1']"
:mode="mode"
:theme="theme"
>
<a-menu-item key="1">
<a-icon type="mail" />
Navigation One
</a-menu-item>
<a-menu-item key="2">
<a-icon type="calendar" />
Navigation Two
</a-menu-item>
<a-sub-menu key="sub1">
<span slot="title"><a-icon type="appstore" /><span>Navigation Three</span></span>
<a-menu-item key="3">
Option 3
</a-menu-item>
<a-menu-item key="4">
Option 4
</a-menu-item>
<a-sub-menu key="sub1-2" title="Submenu">
<a-menu-item key="5">
Option 5
</a-menu-item>
<a-menu-item key="6">
Option 6
</a-menu-item>
</a-sub-menu>
</a-sub-menu>
<a-sub-menu key="sub2">
<span slot="title"><a-icon type="setting" /><span>Navigation Four</span></span>
<a-menu-item key="7">
Option 7
</a-menu-item>
<a-menu-item key="8">
Option 8
</a-menu-item>
<a-menu-item key="9">
Option 9
</a-menu-item>
<a-menu-item key="10">
Option 10
</a-menu-item>
</a-sub-menu>
</a-menu>
</div>
</template>
<script>
export default {
data() {
return {
mode: 'inline',
theme: 'light',
};
},
methods: {
changeMode(checked) {
this.mode = checked ? 'vertical' : 'inline';
},
changeTheme(checked) {
this.theme = checked ? 'dark' : 'light';
},
},
};
</script>
单文件递归菜单
使用单文件方式递归生成菜单。
因组件内部会动态更改a-sub-menu
的属性,如果拆分成单文件,无法将属性挂载到a-sub-menu
上,你需要自行声明属性并挂载。为了方便,避免属性的声明,我们推荐使用函数式组件。
<template>
<div style="width: 256px">
<a-button type="primary" style="margin-bottom: 16px" @click="toggleCollapsed">
<a-icon :type="collapsed ? 'menu-unfold' : 'menu-fold'" />
</a-button>
<a-menu
:default-selected-keys="['1']"
:default-open-keys="['2']"
mode="inline"
theme="dark"
:inline-collapsed="collapsed"
>
<template v-for="item in list">
<a-menu-item v-if="!item.children" :key="item.key">
<a-icon type="pie-chart" />
<span>{{ item.title }}</span>
</a-menu-item>
<sub-menu v-else :key="item.key" :menu-info="item" />
</template>
</a-menu>
</div>
</template>
<script>
// recommend use functional component
// <template functional>
// <a-sub-menu :key="props.menuInfo.key">
// <span slot="title">
// <a-icon type="mail" /><span>{{ props.menuInfo.title }}</span>
// </span>
// <template v-for="item in props.menuInfo.children">
// <a-menu-item v-if="!item.children" :key="item.key">
// <a-icon type="pie-chart" />
// <span>{{ item.title }}</span>
// </a-menu-item>
// <sub-menu v-else :key="item.key" :menu-info="item" />
// </template>
// </a-sub-menu>
// </template>
// export default {
// props: ['menuInfo'],
// };
import { Menu } from 'ant-design-vue';
const SubMenu = {
template: `
<a-sub-menu :key="menuInfo.key" v-bind="$props" v-on="$listeners">
<span slot="title">
<a-icon type="mail" /><span>{{ menuInfo.title }}</span>
</span>
<template v-for="item in menuInfo.children">
<a-menu-item v-if="!item.children" :key="item.key">
<a-icon type="pie-chart" />
<span>{{ item.title }}</span>
</a-menu-item>
<sub-menu v-else :key="item.key" :menu-info="item" />
</template>
</a-sub-menu>
`,
name: 'SubMenu',
// must add isSubMenu: true
isSubMenu: true,
props: {
...Menu.SubMenu.props,
// Cannot overlap with properties within Menu.SubMenu.props
menuInfo: {
type: Object,
default: () => ({}),
},
},
};
export default {
components: {
'sub-menu': SubMenu,
},
data() {
return {
collapsed: false,
list: [
{
key: '1',
title: 'Option 1',
},
{
key: '2',
title: 'Navigation 2',
children: [
{
key: '2.1',
title: 'Navigation 3',
children: [{ key: '2.1.1', title: 'Option 2.1.1' }],
},
],
},
],
};
},
methods: {
toggleCollapsed() {
this.collapsed = !this.collapsed;
},
},
};
</script>
API
<template>
<a-menu>
<a-menu-item>菜单项</a-menu-item>
<a-sub-menu title="子菜单">
<a-menu-item>子菜单项</a-menu-item>
</a-sub-menu>
</a-menu>
</template>
Menu
参数 | 说明 | 类型 | 默认值 |
---|---|---|---|
defaultOpenKeys | 初始展开的 SubMenu 菜单项 key 数组 | ||
defaultSelectedKeys | 初始选中的菜单项 key 数组 | string[] | |
forceSubMenuRender | 在子菜单展示之前就渲染进 DOM | boolean | false |
inlineCollapsed | inline 时菜单是否收起状态 | boolean | - |
inlineIndent | inline 模式的菜单缩进宽度 | number | 24 |
mode | 菜单类型,现在支持垂直、水平、和内嵌模式三种 | string: vertical vertical-right horizontal inline | vertical |
multiple | 是否允许多选 | boolean | false |
openKeys(.sync) | 当前展开的 SubMenu 菜单项 key 数组 | string[] | |
selectable | 是否允许选中 | boolean | true |
selectedKeys(v-model) | 当前选中的菜单项 key 数组 | string[] | |
subMenuCloseDelay | 用户鼠标离开子菜单后关闭延时,单位:秒 | number | 0.1 |
subMenuOpenDelay | 用户鼠标进入子菜单后开启延时,单位:秒 | number | 0 |
theme | 主题颜色 | string: light dark | light |
overflowedIndicator | 自定义 Menu 折叠时的图标 | DOM | <span>···</span> |
Menu 事件
事件名称 | 说明 | 回调参数 |
---|---|---|
click | 点击 MenuItem 调用此函数 | function({ item, key, keyPath }) |
deselect | 取消选中时调用,仅在 multiple 生效 | function({ item, key, selectedKeys }) |
openChange | SubMenu 展开/关闭的回调 | function(openKeys: string[]) |
select | 被选中时调用 | function({ item, key, selectedKeys }) |
Menu.Item
参数 | 说明 | 类型 | 默认值 |
---|---|---|---|
disabled | 是否禁用 | boolean | false |
key | item 的唯一标志 | string | |
title | 设置收缩时展示的悬浮标题 | string |
Menu.SubMenu
参数 | 说明 | 类型 | 默认值 | 版本 |
---|---|---|---|---|
popupClassName | 子菜单样式 | string | 1.5.0 | |
disabled | 是否禁用 | boolean | false | |
key | 唯一标志 | string | ||
title | 子菜单项值 | string|slot |
Menu.SubMenu 的子元素必须是 MenuItem
或者 SubMenu
.
SubMenu 事件
事件名称 | 说明 | 回调参数 |
---|---|---|
titleClick | 点击子菜单标题 | ({ key, domEvent }) |
Menu.ItemGroup
参数 | 说明 | 类型 | 默认值 |
---|---|---|---|
title | 分组标题 | string||function|slot |
Menu.ItemGroup 的子元素必须是 MenuItem
.
Menu.Divider
菜单项分割线,只用在弹出菜单内。