菜单 Menu
要吃东西。
基本用法
通过 Menu、MenuItem、MenuGroup、Submenu 组织菜单结构。MenuItem 接收 href 或 route 参数的时候,渲染围为 <a> 标签或者 Vue Router 的 RouterLink 组件。
WARNING
href 和 route 属性将直接渲染到 <a> 标签中,如果传递类似 javascript:alert(1) 这样的值或恶意 URL,可能会导致 XSS 或开放重定向漏洞。
<template>
<px-menu :default-active="'Home'">
<px-menu-item index="Home" href="/pixelium-design/">
Home
<template #icon>
<IconHome></IconHome>
</template>
</px-menu-item>
<px-submenu index="Components" label="Components">
<template #icon>
<IconBars></IconBars>
</template>
<px-menu-item index="Button">
Button
<template #icon>
<IconArrowAltCircleUp></IconArrowAltCircleUp>
</template>
</px-menu-item>
<px-menu-item index="Input">
Input
<template #icon>
<IconPencil></IconPencil>
</template>
</px-menu-item>
</px-submenu>
<px-menu-group index="More" label="More">
<px-menu-item index="About">
About
<template #icon>
<IconLink></IconLink>
</template>
</px-menu-item>
<px-menu-item
index="Github"
href="https://github.com/shika-works/pixelium-design"
target="_blank"
>
Github
<template #icon>
<IconGithub></IconGithub>
</template>
</px-menu-item>
</px-menu-group>
</px-menu>
</template>
<script setup lang="ts">
import {
IconHome,
IconArrowAltCircleUp,
IconPencil,
IconGithub,
IconLink,
IconBars
} from '@pixelium/web-vue/icon-hn/es'
</script>横向菜单
设置 direction 为 "horizontal" 时,展示横向菜单,ellipsis 为 true 时溢出的菜单项会自动收纳到 ... 子菜单中。
- ...
<template>
<px-menu direction="horizontal" :ellipsis="true">
<px-menu-item :key="i" :index="i" v-for="i in 15">Item {{ i }}</px-menu-item>
</px-menu>
</template>折叠侧栏
侧边栏场景可使用 collapsed 属性以缩略展示菜单。
- Help
<template>
<div>
<px-switch v-model="collapsed" inactive-tip="Expanded" active-tip="Collapsed"></px-switch>
<px-menu :collapsed="collapsed" :default-active="1" style="margin-top: 8px">
<px-menu-item index="Overview">
Overview
<template #icon>
<IconGrid></IconGrid>
</template>
</px-menu-item>
<px-submenu index="Components" label="Components">
<template #icon>
<IconBars></IconBars>
</template>
<px-menu-item index="Input">
Input
<template #icon>
<IconPencil></IconPencil>
</template>
</px-menu-item>
<px-menu-item index="Search">
Search
<template #icon>
<IconSearch></IconSearch>
</template>
</px-menu-item>
</px-submenu>
<px-menu-group index="Help" label="Help">
<px-menu-item index="Document">
Document
<template #icon>
<IconFolder></IconFolder>
</template>
</px-menu-item>
<px-menu-item index="AI">
AI
<template #icon>
<IconRobot></IconRobot>
</template>
</px-menu-item>
</px-menu-group>
</px-menu>
</div>
</template>
<script setup lang="ts">
import {
IconGrid,
IconPencil,
IconSearch,
IconRobot,
IconFolder,
IconBars
} from '@pixelium/web-vue/icon-hn'
import { ref } from 'vue'
const collapsed = ref(true)
</script>分组与子菜单
结合 MenuGroup 与 Submenu 构建多层菜单结构。
- Undead
- Hero
- Death Knight
- Lich
- Unit
- Crypt
- Ghoul
- Crypt Fiend
- Boneyard
- Frost Wyrm
<template>
<px-menu>
<px-menu-group index="Undead" label="Undead">
<px-submenu index="Hero" label="Hero">
<px-menu-item index="Death Knight">Death Knight</px-menu-item>
<px-menu-item index="Lich">Lich</px-menu-item>
</px-submenu>
<px-submenu index="Unit" label="Unit">
<px-submenu index="Crypt" label="Crypt">
<px-menu-item index="Ghoul">Ghoul</px-menu-item>
<px-menu-item index="Crypt Fiend">Crypt Fiend</px-menu-item>
</px-submenu>
<px-submenu index="Boneyard" label="Boneyard">
<px-menu-item index="Frost Wyrm">Frost Wyrm</px-menu-item>
</px-submenu>
</px-submenu>
</px-menu-group>
</px-menu>
</template>强调菜单
设置 Menu dark 属性为 true 开启高对比度的深色模式。
- Home
- Components
- Button
- Input
- More
- About
- Github
<template>
<px-menu :default-active="'Home'" dark>
<px-menu-item index="Home">
Home
<template #icon>
<IconHome></IconHome>
</template>
</px-menu-item>
<px-submenu index="Components" label="Components">
<template #icon>
<IconBars></IconBars>
</template>
<px-menu-item index="Button">
Button
<template #icon>
<IconArrowAltCircleUp></IconArrowAltCircleUp>
</template>
</px-menu-item>
<px-menu-item index="Input">
Input
<template #icon>
<IconPencil></IconPencil>
</template>
</px-menu-item>
</px-submenu>
<px-menu-group index="More" label="More">
<px-menu-item index="About">
About
<template #icon>
<IconLink></IconLink>
</template>
</px-menu-item>
<px-menu-item index="Github">
Github
<template #icon>
<IconGithub></IconGithub>
</template>
</px-menu-item>
</px-menu-group>
</px-menu>
</template>
<script setup lang="ts">
import {
IconHome,
IconArrowAltCircleUp,
IconPencil,
IconGithub,
IconLink,
IconBars
} from '@pixelium/web-vue/icon-hn/es'
</script>选项属性
Menu 的 options 属性用于直接传入选项,可以用于简单菜单的快速创建,选项的字符串值和 index 字段作为菜单子组件的唯一标识,推荐确保它们的唯一性。
<template>
<px-space direction="vertical">
<px-menu :options="optionsHorizontal" direction="horizontal"> </px-menu>
<px-menu :options="optionsVertical"> </px-menu>
</px-space>
</template>
<script setup lang="ts">
import {
IconHome,
IconArrowAltCircleUp,
IconPencil,
IconGithub,
IconLink,
IconBars
} from '@pixelium/web-vue/icon-hn/es'
import { h, ref } from 'vue'
const optionsVertical = ref([
{
label: 'Home',
index: 'Home',
href: '/pixelium-design/',
icon: h(IconHome)
},
{
label: 'Components',
index: 'Components',
icon: h(IconBars),
type: 'submenu',
children: [
{
label: 'Button',
index: 'Button',
icon: h(IconArrowAltCircleUp)
},
{
label: 'Input',
index: 'Input',
icon: h(IconPencil)
}
]
},
{
label: 'More',
index: 'More',
type: 'group',
children: [
{
label: 'About',
index: 'About',
icon: h(IconLink)
},
{
label: 'Github',
index: 'Github',
href: 'https://github.com/shika-works/pixelium-design',
target: '_blank',
icon: h(IconGithub)
},
'Contact us'
]
}
])
const optionsHorizontal = ref([
{
label: 'Home',
index: 'Home',
href: '/pixelium-design/',
icon: h(IconHome)
},
{
label: 'Components',
index: 'Components',
icon: h(IconBars),
type: 'submenu',
children: [
{
label: 'Form',
type: 'submenu',
children: [
{
label: 'Button',
index: 'Button',
icon: h(IconArrowAltCircleUp)
},
{
label: 'Input',
index: 'Input',
icon: h(IconPencil)
}
]
}
]
},
{
label: 'More',
index: 'More',
type: 'submenu',
children: [
{
label: 'Link',
index: 'Link',
type: 'group',
children: [
{
label: 'About',
index: 'About',
icon: h(IconLink)
},
{
label: 'Github',
index: 'Github',
href: 'https://github.com/shika-works/pixelium-design',
target: '_blank',
icon: h(IconGithub)
},
'Contact us'
]
}
]
}
])
</script>受控模式
通过传入 active 和 expanded 控制选中菜单和展开菜单,支持 v-model。不传或为 undefined 则为非受控模式,此时可以通过 defaultActive 和 defaultExpanded 设置默认值。
- Home
- Features
- One
- Two
Active: 1 | Expanded: [
"2"
]
<template>
<div>
<px-menu v-model:active="active" v-model:expanded="expanded">
<px-menu-item index="1">Home</px-menu-item>
<px-submenu index="2" label="Features">
<px-menu-item index="2-1">One</px-menu-item>
<px-menu-item index="2-2">Two</px-menu-item>
</px-submenu>
</px-menu>
<div style="margin-top: 12px">Active: {{ active }} | Expanded: {{ expanded }}</div>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue'
const active = ref('1')
const expanded = ref(['2'])
</script>API
MenuProps
| 属性 | 类型 | 可选 | 默认值 | 描述 | 版本 |
|---|---|---|---|---|---|
| direction | 'horizontal' | 'vertical' | 是 | 'vertical' | 菜单的方向 | 0.1.0 |
| dark | boolean | 是 | false | 菜单是否为深色模式。 | 0.1.0 |
| active | number | string | symbol | null | 是 | | 激活的菜单项,支持 v-model 受控模式。 | 0.1.0 |
| defaultActive | number | string | symbol | null | 是 | | 激活的菜单项的默认值,非受控模式。 | 0.1.0 |
| expanded | (number | string | symbol)[] | null | 是 | | 展开的子菜单,支持 v-model 受控模式。 | 0.1.0 |
| defaultExpanded | (number | string | symbol)[] | null | 是 | | 展开的子菜单默认值,非受控模式。 | 0.1.0 |
| collapsed | boolean | 是 | false | 垂直菜单是否折叠。 | 0.1.0 |
| submenuMode | 'inline' | 'popover' | 是 | 'inline' | 子菜单展示方式,若子菜单 mode 未设置将采用该值。 | 0.1.0 |
| submenuTrigger | 'hover' | 'click' | 是 | 'hover' | 子菜单浮窗的触发方式,若子菜单 trigger 未设置将采用该值。 | 0.1.0 |
| indent | number | 是 | 16 | 每级菜单的缩进。 | 0.1.0 |
| ellipsis | boolean | 是 | true | 横向菜单超出部分是否收纳到 ... 子菜单中。 | 0.1.0 |
| options | (string | MenuOption | MenuGroupOption | SubmenuOption)[] | 是 | | 用于创建菜单子组件的选项,当未传入 default 插槽时生效。 | 0.1.0 |
MenuEvents
| 事件 | 参数 | 描述 | 版本 |
|---|---|---|---|
| update:active | value: number | string | symbol | 更新 active 的回调。 | 0.1.0 |
| update:expend | value: (number | string | symbol)[] | 0.1.0 | |
| select | index: number | string | symbol, event: MouseEvent | 选中菜单的回调。 | 0.1.0 |
| expandChange | value: (number | string | symbol)[], event: MouseEvent | 展开的子菜单变化的回调。 | 0.1.0 |
| expand | index: number | string | symbol, event: MouseEvent | 展开一个子菜单时触发的回调。 | 0.1.0 |
| fold | index: number | string | symbol, event: MouseEvent | 折叠一个子菜单时触发的回调。 | 0.1.0 |
MenuSlots
| 插槽 | 参数 | 描述 | 版本 |
|---|---|---|---|
| default | | 构成菜单的子组件们。 | 0.1.0 |
MenuItemProps
| 属性 | 类型 | 可选 | 默认值 | 描述 | 版本 |
|---|---|---|---|---|---|
| label | string | 是 | | 文本标签。 | 0.1.0 |
| index | number | string | symbol | 否 | | 唯一标识,MenuItem 和 Submenu 组件的 index 属性不可重复。 | 0.1.0 |
| disabled | boolean | 是 | false | 是否禁用。 | 0.1.0 |
| route | string | object | 是 | | Vue Router 的 RouterLink 的 to 参数,传入后,将以 RouterLink 作为 <a> 渲染文本标签。如果使用该属性,请确保在全局的 Vue App 中注册 Vue Router。 | 0.1.0 |
| href | string | 是 | | <a> 标签的 href 属性,传入 href 参数时,将以 <a> 标签渲染文本标签。 | 0.1.0 |
| target | string | 是 | | <a> 标签的 target 属性。 | 0.1.0 |
MenuItemSlots
| 插槽 | 参数 | 描述 | 版本 |
|---|---|---|---|
| default | | 文本标签。 | 0.1.0 |
| icon | | 图标。 | 0.1.0 |
SubmenuProps
| 属性 | 类型 | 可选 | 默认值 | 描述 | 版本 |
|---|---|---|---|---|---|
| label | string | 是 | | 文本标签。 | 0.1.0 |
| index | number | string | symbol | 否 | | 唯一标识,MenuItem 和 Submenu 组件的 index 属性不可重复。 | 0.1.0 |
| disabled | boolean | 是 | false | 是否禁用。 | 0.1.0 |
| mode | boolean | 是 | | 子菜单展示方式,inline 为内联的下拉子菜单,popover 为弹出框展示的浮窗子菜单。值为 inline 只在垂直菜单中和非浮窗子菜单中生效。 | 0.1.0 |
| trigger | boolean | 是 | | 子菜单的浮窗触发方式。 | 0.1.0 |
| popoverProps | Omit<PopoverProps, 'visible' | 'defaultVisible' | 'content'> & EmitEvent<PopoverEvents> | 是 | | 内部 Popover 的属性。 | 0.1.0 |
SubmenuSlots
| 插槽 | 参数 | 描述 | 版本 |
|---|---|---|---|
| default | | 构成菜单的子组件们。 | 0.1.0 |
| label | | 文本标签。 | 0.1.0 |
| icon | | 图标。 | 0.1.0 |
MenuGroupProps
| 属性 | 类型 | 可选 | 默认值 | 描述 | 版本 |
|---|---|---|---|---|---|
| label | string | 是 | | 文本标签。 | 0.1.0 |
MenuGroupSlots
| 插槽 | 参数 | 描述 | 版本 |
|---|---|---|---|
| default | | 构成菜单的子组件们。 | 0.1.0 |
| label | | 文本标签。 | 0.1.0 |
MenuOption, MenuGroupOption, SubmenuOption
ts
export interface MenuOption extends NavigationOption {
disabled?: boolean
href?: string
route?: string | object
target?: string
icon?: () => ValidVNodeContent
}
export interface MenuGroupOption extends NavigationOption {
children: (string | MenuOption | MenuGroupOption | SubmenuOption)[]
type: 'group'
}
export interface SubmenuOption extends NavigationOption {
children: (string | MenuOption | MenuGroupOption | SubmenuOption)[]
disabled?: boolean
type: 'submenu'
icon?: () => ValidVNodeContent
}
export interface NavigationOption {
index: string | number | symbol
label?: string
}
export type ValidVNodeContent = (...args: any[]) => VNode | JSX.Element1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
EmitEvent
ts
export type EmitEvent<T extends Record<string, any>> = {
[K in keyof T as `on${Capitalize<K & string>}`]?: (...args: T[K]) => void
}1
2
3
2
3