菜单
概述
Menu 组件家族用于构建复杂的嵌套菜单(支持下拉菜单与右键菜单)。它提供数据驱动方式:通过 SMenuOptions、SMenuCheckboxOptions、SMenuRadioOptions 轻松配置分组、子菜单、复选项、单选项、分隔线、快捷键与链接项。逻辑层复用 @vean/aria/menu,具备完整的 WAI-ARIA 菜单语义与 roving-focus 键盘导航。
功能特性
- 数据驱动的 Compact 组合 —
SMenuOptions/SMenuCheckboxOptions/SMenuRadioOptions从items数组递归渲染条目;AriaMenuOptionsCompact负责迭代、默认装配与子菜单递归。 - 完整 WAI-ARIA 菜单语义 —
role="menu"/menuitem/menuitemcheckbox/menuitemradio,aria-checked(含'mixed')、aria-haspopup、aria-expanded、aria-controls、aria-disabled。 - 完整键盘导航 — roving focus 方向键移动(dir 感知)、Typeahead 字符搜索(过滤禁用项)、Home/End/PageUp/PageDown 跳转、Enter/Space 选中、Esc 关闭并归还焦点、Tab 在菜单内循环、子菜单方向键打开/关闭。
- 浮层定位 — 基于
@floating-ui/dom(autoUpdate+arrow/flip/hide/limitShift/offset/shift/size中间件),支持 arrow、placement、sideOffset 与 CSS 变量传递。 - 三种数据形态 — 普通
MenuOptionData(图标/快捷键/分隔线/链接/子菜单)、复选MenuCheckboxOptionData(CheckedState含'mixed')、单选MenuRadioOptionData(AcceptableBooleanValue),各带独立 group。 - 分组与分隔 —
isGroupLabel渲染MenuGroupLabel分组标题,separator渲染分隔线,shortcut渲染快捷键提示。 - 浮层生命周期 — dismissable layer(点击外部/Esc 关闭)、Presence(退出动画 +
forceMount)、body scroll lock、focus scope/trap、modal 模式。 - 禁用项 — 逐项
disabled与itemProps.disabled全局兜底(显式项值优先),aria-disabled+tabindex="-1"。 - 隐藏项 — 逐项
hidden将该条目及其整棵子树从渲染结果、激活路径查找与键盘导航中移除;子项全部隐藏的条目按叶子节点渲染。 - Aria 组合 —
MenuRoot/MenuContent/MenuItem/MenuCheckboxItem/MenuRadioItem/MenuSub/MenuGroup等从@vean/aria/menu导出,供下拉菜单、右键菜单、菜单栏复用。
组件家族
SMenuOptions— 数据驱动的普通菜单项列表(含子菜单/链接/分隔线/快捷键)。SMenuOption— 递归条目组件,SMenuOptions内部使用(可独立使用)。SMenuCheckboxOptions— 复选菜单项组(v-model绑定数组 /CheckedState)。SMenuRadioOptions— 单选菜单项组(v-model绑定AcceptableBooleanValue)。
用法
演示
基础
API
Aria 层
27ContextMenuPopup
MenuAnchor
MenuArrow
MenuCheckboxGroup<T extends DefinedValue = DefinedValue>
属性
| 属性名 | 类型 | 默认值 | 描述 |
|---|---|---|---|
modelValue | T[] | — | 复选框的受控值。可通过 v-model 进行绑定。 |
defaultValue | T[] | — | 复选框在初始渲染时的值。当不需要控制其值时使用。 |
disabled | boolean | false | 当值为 `true` 时,禁止用户与复选框进行交互 |
asChild | boolean | — | 将默认渲染元素替换为作为子元素传递的元素,并合并两者的属性及行为。 |
as | AsTag | Component | 'div' | 该组件应渲染为的元素或组件。可通过 `asChild` 进行覆盖。 |
事件
| 事件名 | 参数 | 描述 |
|---|---|---|
update:modelValue | T[] | 当复选框组的值发生变化时调用的事件处理程序。 |
MenuCheckboxItem
属性
| 属性名 | 类型 | 默认值 | 描述 |
|---|---|---|---|
modelValue | CheckedState | — | 该控件的已选中状态。可作为 `v-model` 使用。 |
value | DefinedValue | on | 作为数据提交时与 `name` 关联的值。 |
disabled | boolean | — | 当值为 `true` 时,禁止用户与该项进行交互。 |
textValue | string | — | 用于联想输入的可选文本。默认情况下,联想输入功能将使用该
项的 `.textContent`。<br> 当内容较为复杂,或其中包含非文本内容时,请使用此选项。 |
asChild | boolean | — | 将默认渲染元素替换为作为子元素传递的元素,并合并两者的属性及行为。 |
as | AsTag | Component | 'div' | 该组件应渲染为的元素或组件。可通过 `asChild` 进行覆盖。 |
事件
| 事件名 | 参数 | 描述 |
|---|---|---|
select | Event | 当用户(通过鼠标或键盘)选择某项时调用的事件处理程序。<br> 在
此处理程序中调用 `event.preventDefault` 将阻止在选择该项时关闭菜单。 |
update:modelValue | CheckedState | 当项的选中状态发生变化时,会调用此事件处理程序。 |
MenuCheckboxOptionsCompact<T>
属性
| 属性名 | 类型 | 默认值 | 描述 |
|---|---|---|---|
items | MenuCheckboxOptionData<T>[] | — | 由该组件渲染的项。 |
groupLabelProps | MenuGroupLabelProps | — | 转发至组标签元素的属性。 |
checkboxItemProps | MenuCheckboxItemProps | — | 转发给复选框项元素的属性。 |
indicatorProps | MenuItemIndicatorProps | — | 转发给 indicator 元素的属性。 |
shortcutProps | MenuShortcutProps | — | 转发给快捷方式元素的属性。 |
separatorProps | MenuSeparatorProps | — | 转发给分隔符元素的属性。 |
modelValue | T[] | — | 复选框的受控值。可通过 v-model 进行绑定。 |
defaultValue | T[] | — | 复选框在初始渲染时的值。当不需要控制其值时使用。 |
disabled | boolean | false | 当值为 `true` 时,禁止用户与复选框进行交互 |
asChild | boolean | — | 将默认渲染元素替换为作为子元素传递的元素,并合并两者的属性及行为。 |
as | AsTag | Component | 'div' | 该组件应渲染为的元素或组件。可通过 `asChild` 进行覆盖。 |
事件
| 事件名 | 参数 | 描述 |
|---|---|---|
update:modelValue | T[] | 当复选框组的值发生变化时调用的事件处理程序。 |
select | MenuCheckboxOptionData<T>, event: Event | 在发生 select 事件时触发。 |
插槽
| 插槽名 | 参数 | 描述 |
|---|---|---|
item | MenuCheckboxOptionData<T> | 项插槽的自定义内容。 |
item-leading | MenuCheckboxOptionData<T> | 用于项目引导槽位的自定义内容。 |
item-trailing | MenuCheckboxOptionData<T> | 用于项目尾部槽位的自定义内容。 |
item-indicator-icon | MenuCheckboxOptionData<T> | 项目指示器图标槽位的自定义内容。 |
MenuCheckboxOptionsCompactSelect<T>
事件
| 事件名 | 参数 | 描述 |
|---|---|---|
select | MenuCheckboxOptionData<T>, event: Event | 在发生 select 事件时触发。 |
MenuContent
属性
| 属性名 | 类型 | 默认值 | 描述 |
|---|---|---|---|
popupProps | MenuPopupProps | — | 转发给弹出窗口元素的属性。 |
placement | Placement | undefined | 浮动元素的位置。
若使用该属性,它将覆盖 `side` 和 `align` 属性。 |
side | Side | 'bottom' | 打开时优先渲染的触发器一侧。当发生碰撞且
enableAvoidCollisions 启用时,该方向将被反转。 |
sideOffset | number | 0 | 距触发器的像素距离。 |
sideFlip | boolean | true | 遇到边界时,请翻转至另一侧。 |
align | Align | 'center' | 首选与触发条件保持一致。若发生冲突,则可能调整。 |
alignOffset | number | 0 | 相对于 `start` 或 `end` 对齐选项的像素偏移量。 |
alignFlip | boolean | true | 当与边界发生冲突时,翻转对齐方式。
此情况仅在 `prioritizePosition` 为 true 时才会发生。 |
avoidCollisions | boolean | true | 当值为 `true` 时,将覆盖“侧边”和“对齐”首选项,以避免与边界边缘发生冲突。 |
collisionBoundary | Element | (Element | null)[] | null | [ ] | 用作碰撞边界的元素。默认情况下,该边界为视口,但您可以提供额外的
元素以纳入此检查范围。 |
collisionPadding | Padding | 0 | 从边界边缘开始,碰撞检测应发生的距离(以像素为单位)。接受一个数字(
所有边均相同),或一个部分填充对象,例如:{ top: 20, left: 20 }。 |
arrowPadding | number | 0 | 箭头与内容边缘之间的间距。如果您的内容使用了 border-radius,这将防止内容
溢出到角落。 |
hideShiftedArrow | boolean | true | 当值为 `true` 时,若无法将箭头居中对齐
到引用元素上,则隐藏该箭头。 |
sticky | 'partial' | 'always' | 'partial' | 在对齐轴上的“粘附”行为。`partial` 会在触发器至少部分位于边界内时将内容保留在边界内,而
“always” 则无论触发器是否位于边界内,都会将内容保留在边界内。 |
hideWhenDetached | boolean | false | 当触发器被完全遮挡时,是否隐藏内容。 |
positionStrategy | 'fixed' | 'absolute' | 'fixed' | 要使用的 CSS `position` 属性的类型。 |
updatePositionStrategy | 'always' | 'optimized' | 'optimized' | 在每个动画帧中更新浮动元素位置的策略。 |
disableUpdateOnLayoutShift | boolean | false | 当布局发生变化时,是否禁用内容的更新位置。 |
prioritizePosition | boolean | false | 强制内容位于视口内。可能会与参考元素重叠,这可能并非预期效果。 |
reference | ReferenceElement | — | 将作为浮动元素定位参考点的自定义元素或虚拟元素。如果
提供了该元素,它将替换默认的锚点元素。 |
trapFocus | boolean | modal | 弹出窗口打开时,焦点是否被困在其中(Tab 键在层内循环,且
模态层的页面滚动被锁定)。 |
disableHoverableContent | boolean | false | 当设置为 `true` 时,鼠标悬停会关闭弹出窗口而非保持其打开状态(宽限区域已禁用,
因此离开触发区域会立即关闭该层)。 |
onGracePointerExit | (() => void) | — | 当指针最终离开宽限区域时触发的回调。允许上层组件(例如
Tooltip)在无需注册自己的第二个宽限区域的情况下,执行区域范围内的关闭逻辑。 |
forceMount | boolean | — | 用于在需要更多控制时强制挂载。
在使用 Vue 动画库控制动画时非常有用。 |
loop | boolean | false | 键盘导航是否应循环往复 |
事件
| 事件名 | 参数 | 描述 |
|---|---|---|
escapeKeyDown | KeyboardEvent | 当 Esc 键被按下时触发的事件处理程序。可被阻止。 |
pointerDownOutside | PointerDownOutsideEvent | 当 `pointerdown` 事件发生在 `DismissableLayer` 外部时调用的事件处理程序。可被阻止。 |
focusOutside | FocusOutsideEvent | 当焦点移出 `DismissableLayer` 时触发的事件处理程序。可被阻止。 |
interactOutside | PointerDownOutsideEvent | FocusOutsideEvent | 当在 `DismissableLayer` 外部发生交互时触发的事件处理程序。具体而言,当 `pointerdown`
事件在该区域外部发生,或焦点移出该区域时触发。此事件可被阻止。 |
openAutoFocus | Event | 在打开页面时自动聚焦时触发的事件处理程序。可被阻止。 |
closeAutoFocus | Event | 在关闭时自动聚焦时触发的事件处理程序。可被阻止。 |
entryFocus | Event | 在条目获得焦点时触发。 |
MenuGroup
属性
| 属性名 | 类型 | 默认值 | 描述 |
|---|---|---|---|
asChild | boolean | — | 将默认渲染元素替换为作为子元素传递的元素,并合并两者的属性及行为。 |
as | AsTag | Component | 'div' | 该组件应渲染为的元素或组件。可通过 `asChild` 进行覆盖。 |
MenuGroupLabel
MenuItem
属性
| 属性名 | 类型 | 默认值 | 描述 |
|---|---|---|---|
disabled | boolean | — | 当值为 `true` 时,禁止用户与该项进行交互。 |
textValue | string | — | 用于联想输入的可选文本。默认情况下,联想输入功能将使用该
项的 `.textContent`。<br> 当内容较为复杂,或其中包含非文本内容时,请使用此选项。 |
asChild | boolean | — | 将默认渲染元素替换为作为子元素传递的元素,并合并两者的属性及行为。 |
as | AsTag | Component | 'div' | 该组件应渲染为的元素或组件。可通过 `asChild` 进行覆盖。 |
事件
| 事件名 | 参数 | 描述 |
|---|---|---|
select | Event | 当用户(通过鼠标或键盘)选择某项时调用的事件处理程序。<br> 在
此处理程序中调用 `event.preventDefault` 将阻止在选择该项时关闭菜单。 |
MenuItemIndicator
属性
| 属性名 | 类型 | 默认值 | 描述 |
|---|---|---|---|
forceMount | boolean | — | 用于在需要更多控制时强制挂载。
在使用 Vue 动画库控制动画时非常有用。 |
asChild | boolean | — | 将默认渲染元素替换为作为子元素传递的元素,并合并两者的属性及行为。 |
as | AsTag | Component | 'div' | 该组件应渲染为的元素或组件。可通过 `asChild` 进行覆盖。 |
MenuOptionCompact<T>
属性
| 属性名 | 类型 | 默认值 | 描述 |
|---|---|---|---|
item | MenuOptionData<T extends DefinedValue = DefinedValue> | — | 当前条目数据。 |
itemProps | MenuItemProps | — | 转发给 item 元素的属性。 |
linkProps | LinkExtraProps | — | 传递给 link 元素的属性。 |
groupProps | MenuGroupProps | — | 转发给 group 元素的属性。 |
groupLabelProps | MenuGroupLabelProps | — | 转发至组标签元素的属性。 |
subProps | MenuSubProps | — | 转发给子元素的属性。 |
subTriggerProps | MenuSubTriggerProps | — | 转发给子触发器元素的属性。 |
portalProps | PortalProps | — | 转发给 portal 元素的属性。 |
subContentProps | MenuSubContentProps | — | 转发至子内容元素的属性。 |
separatorProps | MenuSeparatorProps | — | 转发给分隔符元素的属性。 |
shortcutProps | MenuShortcutProps | — | 转发给快捷方式元素的属性。 |
事件
| 事件名 | 参数 | 描述 |
|---|---|---|
update:open | boolean | 当对话框的打开状态发生变化时调用的事件处理程序。 |
escapeKeyDown | KeyboardEvent | 当 Esc 键被按下时触发的事件处理程序。可被阻止。 |
pointerDownOutside | PointerDownOutsideEvent | 当 `pointerdown` 事件发生在 `DismissableLayer` 外部时调用的事件处理程序。可被阻止。 |
focusOutside | FocusOutsideEvent | 当焦点移出 `DismissableLayer` 时触发的事件处理程序。可被阻止。 |
interactOutside | PointerDownOutsideEvent | FocusOutsideEvent | 当在 `DismissableLayer` 外部发生交互时触发的事件处理程序。具体而言,当 `pointerdown`
事件在该区域外部发生,或焦点移出该区域时触发。此事件可被阻止。 |
openAutoFocus | Event | 在打开页面时自动聚焦时触发的事件处理程序。可被阻止。 |
closeAutoFocus | Event | 在关闭时自动聚焦时触发的事件处理程序。可被阻止。 |
entryFocus | Event | 在条目获得焦点时触发。 |
select | MenuOptionData<T>, event: Event | 在发生 select 事件时触发。 |
插槽
| 插槽名 | 参数 | 描述 |
|---|---|---|
item | { item: MenuOptionData<T>; isTrigger?: boolean; } | 项插槽的自定义内容。 |
item-leading | { item: MenuOptionData<T>; } | 用于项目引导槽位的自定义内容。 |
item-trailing | { item: MenuOptionData<T>; } | 用于项目尾部槽位的自定义内容。 |
item-trigger-icon | { item: MenuOptionData<T>; } | 项目触发图标槽位的自定义内容。 |
item-link-icon | { item: MenuOptionData<T>; } | 项目链接图标槽位的自定义内容。 |
MenuOptionCompactSelect<T>
事件
| 事件名 | 参数 | 描述 |
|---|---|---|
select | MenuOptionData<T>, event: Event | 在发生 select 事件时触发。 |
MenuOptionsCompact<T>
属性
| 属性名 | 类型 | 默认值 | 描述 |
|---|---|---|---|
items | MenuOptionData<T>[] | — | 由该组件渲染的项。 |
selectedValue | T | — | 菜单中的选定值。 |
itemProps | MenuItemProps | — | 转发给 item 元素的属性。 |
linkProps | LinkExtraProps | — | 传递给 link 元素的属性。 |
subProps | MenuSubProps | — | 转发给子元素的属性。 |
groupProps | MenuGroupProps | — | 转发给 group 元素的属性。 |
groupLabelProps | MenuGroupLabelProps | — | 转发至组标签元素的属性。 |
shortcutProps | MenuShortcutProps | — | 转发给快捷方式元素的属性。 |
separatorProps | MenuSeparatorProps | — | 转发给分隔符元素的属性。 |
subTriggerProps | MenuSubTriggerProps | — | 转发给子触发器元素的属性。 |
subContentProps | MenuSubContentProps | — | 转发至子内容元素的属性。 |
portalProps | PortalProps | — | 转发给 portal 元素的属性。 |
事件
| 事件名 | 参数 | 描述 |
|---|---|---|
update:open | boolean | 当对话框的打开状态发生变化时调用的事件处理程序。 |
escapeKeyDown | KeyboardEvent | 当 Esc 键被按下时触发的事件处理程序。可被阻止。 |
pointerDownOutside | PointerDownOutsideEvent | 当 `pointerdown` 事件发生在 `DismissableLayer` 外部时调用的事件处理程序。可被阻止。 |
focusOutside | FocusOutsideEvent | 当焦点移出 `DismissableLayer` 时触发的事件处理程序。可被阻止。 |
interactOutside | PointerDownOutsideEvent | FocusOutsideEvent | 当在 `DismissableLayer` 外部发生交互时触发的事件处理程序。具体而言,当 `pointerdown`
事件在该区域外部发生,或焦点移出该区域时触发。此事件可被阻止。 |
openAutoFocus | Event | 在打开页面时自动聚焦时触发的事件处理程序。可被阻止。 |
closeAutoFocus | Event | 在关闭时自动聚焦时触发的事件处理程序。可被阻止。 |
entryFocus | Event | 在条目获得焦点时触发。 |
select | MenuOptionData<T>, event: Event | 在发生 select 事件时触发。 |
插槽
| 插槽名 | 参数 | 描述 |
|---|---|---|
item | { item: MenuOptionData<T>; isTrigger?: boolean; } | 项插槽的自定义内容。 |
item-leading | { item: MenuOptionData<T>; } | 用于项目引导槽位的自定义内容。 |
item-trailing | { item: MenuOptionData<T>; } | 用于项目尾部槽位的自定义内容。 |
item-trigger-icon | { item: MenuOptionData<T>; } | 项目触发图标槽位的自定义内容。 |
item-link-icon | { item: MenuOptionData<T>; } | 项目链接图标槽位的自定义内容。 |
MenuPortal
MenuRadioGroup<T = AcceptableBooleanValue>
属性
| 属性名 | 类型 | 默认值 | 描述 |
|---|---|---|---|
modelValue | T | null | — | 要选中的单选按钮项的控制值。可作为 `v-model` 进行绑定。 |
defaultValue | T | — | 初始渲染时应选中的单选按钮选项的值。当您无需控制
单选按钮选项的状态时使用此选项。 |
disabled | boolean | — | 当值为 `true` 时,禁止用户与单选按钮交互。 |
asChild | boolean | — | 将默认渲染元素替换为作为子元素传递的元素,并合并两者的属性及行为。 |
as | AsTag | Component | 'div' | 该组件应渲染为的元素或组件。可通过 `asChild` 进行覆盖。 |
事件
| 事件名 | 参数 | 描述 |
|---|---|---|
update:modelValue | Exclude<T, undefined> | null | 当单选按钮组值发生变化时调用的事件处理程序 |
MenuRadioItem
属性
| 属性名 | 类型 | 默认值 | 描述 |
|---|---|---|---|
value | string | number | boolean | — | 作为数据提交时与 `name` 关联的值。 |
disabled | boolean | — | 当值为 `true` 时,禁止用户与该项进行交互。 |
textValue | string | — | 用于联想输入的可选文本。默认情况下,联想输入功能将使用该
项的 `.textContent`。<br> 当内容较为复杂,或其中包含非文本内容时,请使用此选项。 |
asChild | boolean | — | 将默认渲染元素替换为作为子元素传递的元素,并合并两者的属性及行为。 |
as | AsTag | Component | 'div' | 该组件应渲染为的元素或组件。可通过 `asChild` 进行覆盖。 |
事件
| 事件名 | 参数 | 描述 |
|---|---|---|
select | Event | 当用户(通过鼠标或键盘)选择某项时调用的事件处理程序。<br> 在
此处理程序中调用 `event.preventDefault` 将阻止在选择该项时关闭菜单。 |
MenuRadioOptionsCompact<T>
属性
| 属性名 | 类型 | 默认值 | 描述 |
|---|---|---|---|
items | MenuRadioOptionData<T>[] | — | 由该组件渲染的项。 |
groupLabelProps | MenuGroupLabelProps | — | 转发至组标签元素的属性。 |
radioItemProps | MenuRadioItemProps | — | 转发给 radio item 元素的属性。 |
indicatorProps | MenuItemIndicatorProps | — | 转发给 indicator 元素的属性。 |
shortcutProps | MenuShortcutProps | — | 转发给快捷方式元素的属性。 |
separatorProps | MenuSeparatorProps | — | 转发给分隔符元素的属性。 |
modelValue | T | null | — | 要选中的单选按钮项的控制值。可作为 `v-model` 进行绑定。 |
defaultValue | T | — | 初始渲染时应选中的单选按钮选项的值。当您无需控制
单选按钮选项的状态时使用此选项。 |
disabled | boolean | — | 当值为 `true` 时,禁止用户与单选按钮交互。 |
asChild | boolean | — | 将默认渲染元素替换为作为子元素传递的元素,并合并两者的属性及行为。 |
as | AsTag | Component | 'div' | 该组件应渲染为的元素或组件。可通过 `asChild` 进行覆盖。 |
事件
| 事件名 | 参数 | 描述 |
|---|---|---|
update:modelValue | Exclude<T, undefined> | null | 当单选按钮组值发生变化时调用的事件处理程序 |
select | MenuRadioOptionData<T>, event: Event | 在发生 select 事件时触发。 |
插槽
| 插槽名 | 参数 | 描述 |
|---|---|---|
item | MenuRadioOptionData<T> | 项插槽的自定义内容。 |
item-leading | MenuRadioOptionData<T> | 用于项目引导槽位的自定义内容。 |
item-trailing | MenuRadioOptionData<T> | 用于项目尾部槽位的自定义内容。 |
item-indicator-icon | MenuRadioOptionData<T> | 项目指示器图标槽位的自定义内容。 |
MenuRadioOptionsCompactSelect<T>
事件
| 事件名 | 参数 | 描述 |
|---|---|---|
select | MenuRadioOptionData<T>, event: Event | 在发生 select 事件时触发。 |
MenuRoot
属性
| 属性名 | 类型 | 默认值 | 描述 |
|---|---|---|---|
dir | Direction | — | 如适用,请指定下拉列表的阅读方向。
若省略,则从全局 `ConfigProvider` 继承,或默认采用 LTR(从左到右)阅读模式。 |
open | boolean | undefined | 对话框的受控打开状态。可通过 `v-model:open` 进行绑定。 |
defaultOpen | boolean | false | 对话框在初始渲染时的打开状态。当无需控制其打开状态时使用。 |
modal | boolean | true | 对话框的模态属性。当设置为 `true` 时,将禁用与外部元素的交互,屏幕阅读器仅能读取对话框
内容。 |
事件
| 事件名 | 参数 | 描述 |
|---|---|---|
update:open | boolean | 当对话框的打开状态发生变化时调用的事件处理程序。 |
MenuSeparator
MenuShortcut
属性
| 属性名 | 类型 | 默认值 | 描述 |
|---|---|---|---|
symbolize | boolean | true | 是否将命令值转换为符号表示形式。 |
MenuSub
属性
| 属性名 | 类型 | 默认值 | 描述 |
|---|---|---|---|
open | boolean | undefined | 对话框的受控打开状态。可通过 `v-model:open` 进行绑定。 |
defaultOpen | boolean | false | 对话框在初始渲染时的打开状态。当无需控制其打开状态时使用。 |
事件
| 事件名 | 参数 | 描述 |
|---|---|---|
update:open | boolean | 当对话框的打开状态发生变化时调用的事件处理程序。 |
MenuSubContent
属性
| 属性名 | 类型 | 默认值 | 描述 |
|---|---|---|---|
loop | boolean | false | 键盘导航是否应循环往复 |
placement | Placement | undefined | 浮动元素的位置。
若使用该属性,它将覆盖 `side` 和 `align` 属性。 |
popupProps | MenuPopupProps | — | 转发给弹出窗口元素的属性。 |
sideOffset | number | 0 | 距触发器的像素距离。 |
arrowPadding | number | 0 | 箭头与内容边缘之间的间距。如果您的内容使用了 border-radius,这将防止内容
溢出到角落。 |
updatePositionStrategy | 'always' | 'optimized' | 'optimized' | 在每个动画帧中更新浮动元素位置的策略。 |
sideFlip | boolean | true | 遇到边界时,请翻转至另一侧。 |
alignOffset | number | 0 | 相对于 `start` 或 `end` 对齐选项的像素偏移量。 |
alignFlip | boolean | true | 当与边界发生冲突时,翻转对齐方式。
此情况仅在 `prioritizePosition` 为 true 时才会发生。 |
avoidCollisions | boolean | true | 当值为 `true` 时,将覆盖“侧边”和“对齐”首选项,以避免与边界边缘发生冲突。 |
collisionBoundary | Element | (Element | null)[] | null | [ ] | 用作碰撞边界的元素。默认情况下,该边界为视口,但您可以提供额外的
元素以纳入此检查范围。 |
collisionPadding | Padding | 0 | 从边界边缘开始,碰撞检测应发生的距离(以像素为单位)。接受一个数字(
所有边均相同),或一个部分填充对象,例如:{ top: 20, left: 20 }。 |
hideShiftedArrow | boolean | true | 当值为 `true` 时,若无法将箭头居中对齐
到引用元素上,则隐藏该箭头。 |
sticky | 'partial' | 'always' | 'partial' | 在对齐轴上的“粘附”行为。`partial` 会在触发器至少部分位于边界内时将内容保留在边界内,而
“always” 则无论触发器是否位于边界内,都会将内容保留在边界内。 |
hideWhenDetached | boolean | false | 当触发器被完全遮挡时,是否隐藏内容。 |
positionStrategy | 'fixed' | 'absolute' | 'fixed' | 要使用的 CSS `position` 属性的类型。 |
disableUpdateOnLayoutShift | boolean | false | 当布局发生变化时,是否禁用内容的更新位置。 |
prioritizePosition | boolean | false | 强制内容位于视口内。可能会与参考元素重叠,这可能并非预期效果。 |
reference | ReferenceElement | — | 将作为浮动元素定位参考点的自定义元素或虚拟元素。如果
提供了该元素,它将替换默认的锚点元素。 |
trapFocus | boolean | modal | 弹出窗口打开时,焦点是否被困在其中(Tab 键在层内循环,且
模态层的页面滚动被锁定)。 |
disableHoverableContent | boolean | false | 当设置为 `true` 时,鼠标悬停会关闭弹出窗口而非保持其打开状态(宽限区域已禁用,
因此离开触发区域会立即关闭该层)。 |
onGracePointerExit | (() => void) | — | 当指针最终离开宽限区域时触发的回调。允许上层组件(例如
Tooltip)在无需注册自己的第二个宽限区域的情况下,执行区域范围内的关闭逻辑。 |
forceMount | boolean | — | 用于在需要更多控制时强制挂载。
在使用 Vue 动画库控制动画时非常有用。 |
事件
| 事件名 | 参数 | 描述 |
|---|---|---|
escapeKeyDown | KeyboardEvent | 当 Esc 键被按下时触发的事件处理程序。可被阻止。 |
pointerDownOutside | PointerDownOutsideEvent | 当 `pointerdown` 事件发生在 `DismissableLayer` 外部时调用的事件处理程序。可被阻止。 |
focusOutside | FocusOutsideEvent | 当焦点移出 `DismissableLayer` 时触发的事件处理程序。可被阻止。 |
interactOutside | PointerDownOutsideEvent | FocusOutsideEvent | 当在 `DismissableLayer` 外部发生交互时触发的事件处理程序。具体而言,当 `pointerdown`
事件在该区域外部发生,或焦点移出该区域时触发。此事件可被阻止。 |
openAutoFocus | Event | 在打开页面时自动聚焦时触发的事件处理程序。可被阻止。 |
closeAutoFocus | Event | 在关闭时自动聚焦时触发的事件处理程序。可被阻止。 |
entryFocus | Event | 在条目获得焦点时触发。 |
MenuSubTrigger
属性
| 属性名 | 类型 | 默认值 | 描述 |
|---|---|---|---|
disabled | boolean | — | 当值为 `true` 时,禁止用户与该项进行交互。 |
textValue | string | — | 用于联想输入的可选文本。默认情况下,联想输入功能将使用该
项的 `.textContent`。<br> 当内容较为复杂,或其中包含非文本内容时,请使用此选项。 |
asChild | boolean | — | 将默认渲染元素替换为作为子元素传递的元素,并合并两者的属性及行为。 |
as | AsTag | Component | 'div' | 该组件应渲染为的元素或组件。可通过 `asChild` 进行覆盖。 |
MenuTrigger
属性
| 属性名 | 类型 | 默认值 | 描述 |
|---|---|---|---|
type | ButtonType | 'button' | 按钮元素的类型。可以是 'button'、'submit' 或 'reset' 之一。 |
disabled | boolean | — | 该组件是否已禁用。 |
asChild | boolean | — | 将默认渲染元素替换为作为子元素传递的元素,并合并两者的属性及行为。 |
as | AsTag | Component | 'div' | 该组件应渲染为的元素或组件。可通过 `asChild` 进行覆盖。 |
备注
架构与行业对标
| 关注点 | VeanUI | Radix UI Menu | Ant Design Menu / Dropdown | Element Plus Dropdown |
|---|---|---|---|---|
| Aria / 样式分离 | ✅ @vean/aria/menu + scv() | ✅ Aria 原语 | ❌ 单一包 | ❌ 单一包 |
| 数据驱动 Compact API | ✅ 普通/复选/单选三形态 | ❌ 仅组件组合 | ✅ 配置驱动(items) | ✅ 配置驱动 |
| roving focus + typeahead | ✅ 完整键盘模型(Home/End/PageUp/PageDown) | ✅ | 部分 | 部分 |
| 子菜单方向键 | ✅ ArrowRight/Left(dir 感知) | ✅ | 部分 | 部分 |
| 复选/单选项 | ✅ menuitemcheckbox / menuitemradio | ✅ | ✅ | 部分 |
'mixed' 半选 | ✅ CheckedState | ✅ | ✅ | — |
| 浮层定位 | ✅ floating-ui(arrow/size/flip/…) | ✅ | ✅ | ✅ |
| 分隔线 / 快捷键 | ✅ separator / shortcut | 组件组合 | ✅(divider / command) | 部分 |
| 分组 | ✅ isGroupLabel + MenuGroupLabel | ✅ MenuGroup | ✅(type:‘group’) | 部分 |
— = 不支持或采用不同交互模型。
运行时注意事项
items数据形态 —MenuOptionData含label/value/icon/shortcut/separator/isGroupLabel/children;children递归渲染子菜单。复选/单选形态各有独立类型。- 受控/非受控 — 复选与单选组支持
modelValue/defaultValue(useControllableState);单选组modelValue可为null(无选中)。 - 键盘激活 — roving focus 由
useRovingFocusGroup维护;typeahead在菜单内按字符跳转(过滤禁用项);Esc经useDismissableLayer关闭并归还焦点到 trigger。 - 禁用回退 — 逐项
disabled优先于itemProps.disabled全局兜底;禁用项aria-disabled+tabindex="-1",保持注册以便 typeahead 跳过。 - 浮层生命周期 — dismissable layer + Presence(
forceMount支持);body scroll lock 与 focus scope 由 Root 开启 modal 模式时启用。 - 链接项 — 带
href/to的条目渲染为链接(复用 Link 原语),itemProps/linkProps透传属性。 select事件载荷 —select(item, event)携带被选条目与原生事件;返回前可通过event的defaultPrevented控制菜单是否关闭。
常见问题
如何创建带子菜单的菜单项?
在 MenuOptionData 中提供 children 数组即可递归渲染子菜单;子菜单支持再次嵌套。
复选项与单选项如何绑定值?
复选使用 v-model 绑定数组(CheckedState[],支持 'mixed');单选使用 v-model 绑定 AcceptableBooleanValue(可为 null 表示无选中)。
如何添加分隔线与快捷键?
在条目数据中设置 separator: true 在条目后渲染分隔线;设置 shortcut(KbdValue 或数组)在条目末尾渲染快捷键提示。
键盘如何导航?
方向键移动焦点(dir 感知);输入字母触发 typeahead 跳转;Home/End 跳首尾;Enter/Space 选中;Esc 关闭并归还焦点;Tab 在菜单内循环;子菜单通过 ArrowRight/ArrowLeft 打开/关闭。
可以构建完全自定义的菜单吗?
可以 — 从 @vean/aria/menu 组合 MenuRoot / MenuContent / MenuItem / MenuCheckboxItem / MenuRadioItem / MenuSub / MenuGroup 等原语,并通过 provideMenuUi(或 SMenuOptions 的 ui prop)注入样式。