跳转到内容

菜单 menu

导航组件。三层同源:无头内核给出解剖与状态机,Vue 组件与自定义元素只是它的两层外壳,行为完全一致。

示例

基础用法

collection 是条目的事实源:文本与禁用都写在数据里,trigger / positioner / content / item 由组件铺开

最近选中:(无)

受控

传了 open 就由宿主说了算,组件只发 open-change 不自己改展开态

当前:收起

放置位与箭头

placement 只是首选位,空间不够时定位引擎会自动翻面;arrow 指回触发器

语气

tone 决定条目高亮用哪族颜色;静止态看不出来,展开后悬停条目、或用方向键把焦点移上去才显现

尺寸

size 换的是条目的内边距、间距与字号;三档各挂一个菜单,逐个展开对比

条目里的图标与快捷键

条目内容归作者:前面挂图标、后面挂快捷键,皮肤把它们按 flex 排开

菜单里的非条目内容

content 里可以直接放任意节点;不是 item 就不进方向键行程,也选不中

条目自带的属性与事件

写在条目上的属性直接落到那一层 DOM:原生属性照样透传,自己的 click 与内部的选中处理并存

  1. (还没动过)

悬停展开

触发器与浮层各挂一对进出事件,进出各自延时;两边的延时都由宿主的定时器管

最近选中:(无)

分组与标记位

组标题与组内条目用 role="group" 加 aria-labelledby 对上;中间包一层不影响方向键行程,条目里标记位与文字各占一段

行高:宽松;面板:1 个

产物

自定义元素<xh-menu>
Vue 组件XhMenuArrow XhMenuContent XhMenuItem XhMenuPositioner XhMenuRoot XhMenuSeparator XhMenuTrigger
组合式函数useMenu
状态机menuMachine
皮肤@xihan-ui/styles/menu.css

解剖

部件名即 data-part 属性值,也是皮肤的选择器。加粗的是必备部件,不渲染它组件不工作(Web Components 适配器会在诊断通道上报 wc.missing-part)。

data-scope="menu"trigger · positioner · content · item · separator · arrow

Props

属性类型必填说明
collectionMenuNode[]条目数据,显示文本与禁用的事实源。给了它,条目部件只需报 value。 缺省即回到「文本与禁用都写在条目部件上」的老路。
openboolean展开态,给定即受控;受控下内部不自改,只发 onOpenChange。
defaultOpenboolean
placementPlacement
offsetnumber
loopboolean方向键走到尽头是否回绕,默认 true。
dirDirection文字方向,默认 ltr。
toneTone语气:brand / neutral / success / warning / danger / info,决定条目高亮用哪族颜色。
sizeSize尺寸:sm / md / lg,决定条目高度、内边距与字号档位。
onOpenChange(details: MenuOpenChangeDetails) => voidopen 变化回调。
onSelect(details: MenuSelectDetails) => void条目被选中;菜单随之关闭。

状态机

状态open · closed

事件OPEN · TOGGLE · CLOSE · CONTROLLED.OPEN · CONTROLLED.CLOSE · ITEM.FOCUS · ITEM.LOST · ITEM.SELECT

判据isOpenControlled

connect API

useMenu 产出的对象。getXxxProps() 铺到对应部件的宿主元素上,其余是可读状态与操作入口。

成员类型说明
openboolean
collectionreadonly MenuNodeMeta[]collection 推出的条目元信息,按数据顺序排列;没给 collection 即空数组。
focusedValuestring | null焦点锚点;收起时为 null。
setOpen(next: boolean) => void
getTriggerProps() => T['button']
getPositionerProps() => T['element']
getContentProps() => T['element']
getItemProps(props: MenuItemProps) => T['element']
getSeparatorProps() => T['element']
getArrowProps() => T['element']

键盘

规格出处:W3C APG

按键生效条件行为
Enter / Space / ArrowDownfocus in trigger展开菜单并把焦点落到首个可用条目
ArrowUpfocus in trigger展开菜单并把焦点落到末个可用条目
ArrowDownopen, focus in content焦点移到下一个条目(禁用项跳过、尽头按 loop 回绕)
ArrowUpopen, focus in content焦点移到上一个条目(禁用项跳过、尽头按 loop 回绕)
Homeopen, focus in content焦点移到首个可用条目
Endopen, focus in content焦点移到末个可用条目
Enter / Spacefocus in item, not disabled派发选中详情并关闭菜单,焦点归还 trigger
Escapeopen关闭菜单并把焦点归还 trigger
Tab / Shift+Tabopen关闭菜单,焦点不归还 trigger,按 Tab 序列自然离开

Released under The MIT License