列表框 listbox
数据录入组件。三层同源:无头内核给出解剖与状态机,Vue 组件与自定义元素只是它的两层外壳,行为完全一致。
示例
基础用法
交一份 collection 就够:方向键只搬焦点,Enter 或空格才落值;整组只占一个 Tab 位
已选:beijing
多选
multiple 下空格改成切换该条,Shift + 方向键顺手扩选,Ctrl / Cmd + A 全选或全不选
已选:beijing、london
分组
item-group 把条目分段,group-label 是这一段的可及名字,不参与选中也不接方向键
已选:(无)
选择模式
selection-mode 直接指定三种模式,extended 是「单击换一条、Ctrl 与 Shift 才扩选」
已选:a
弹出式选择
把列表装进浮层:触发器显示当前选中项,落值即收起,浮层底部还能放操作按钮
已选:song1
定高滚动
用 --xh-listbox-content-max-h 压住列表高度,条目多了就在容器里滚;方向键走到哪条,视图跟到哪条
已选:track-1
空态
条目筛空时收起列表、亮出空态节点:它挂在 content 之外,方向键、连打检索与全选都看不见它
没有匹配的成员
换个关键词再试试。
已选:(无)
产物
| 层 | 值 |
|---|---|
| 自定义元素 | <xh-listbox> |
| Vue 组件 | XhListboxContent XhListboxItem XhListboxItemGroup XhListboxItemGroupLabel XhListboxItemIndicator XhListboxItemText XhListboxLabel XhListboxRoot |
| 组合式函数 | useListbox |
| 状态机 | listboxMachine |
| 皮肤 | @xihan-ui/styles/listbox.css |
解剖
部件名即 data-part 属性值,也是皮肤的选择器。加粗的是必备部件,不渲染它组件不工作(Web Components 适配器会在诊断通道上报 wc.missing-part)。
data-scope="listbox":root · label · content · item · item-text · item-indicator · item-group · item-group-label
Props
| 属性 | 类型 | 必填 | 说明 |
|---|---|---|---|
collection | ListboxNode[] | 条目数据,显示文本与禁用的事实源。给了它,条目部件只需报 value。 缺省即回到「文本与禁用都写在条目部件上」的老路。 | |
value | string | string[] | 选中值,给定即受控;单选可写成裸串,内部归一成数组。 | |
defaultValue | string | string[] | ||
multiple | boolean | selectionMode='multiple' 的简写;两者同时给时以 selectionMode 为准。 | |
selectionMode | ListboxSelectionMode | ||
disabled | boolean | 整个列表禁用,键盘与点击都不再改选中值。 | |
loop | boolean | 方向键走到尽头是否回绕,默认 true。 | |
dir | Direction | 文字方向,默认 ltr。 | |
orientation | Orientation | 方向键轴向,默认 vertical。 | |
typeahead | boolean | 连打检索,默认开。 | |
onValueChange | (details: ListboxValueChangeDetails) => void | value 变化意图回调。 |
状态机
状态:idle
事件:VALUE.SET · ITEM.SELECT · ITEM.TOGGLE · ITEM.FOCUS · LIST.BLUR
connect API
useListbox 产出的对象。getXxxProps() 铺到对应部件的宿主元素上,其余是可读状态与操作入口。
| 成员 | 类型 | 说明 |
|---|---|---|
value | string[] | 选中集合;单选模式下长度 ≤ 1。 |
collection | readonly ListboxNodeMeta[] | collection 推出的条目元信息,按数据顺序排列;没给 collection 即空数组。 |
selectionMode | ListboxSelectionMode | 生效的选择模式。 |
focusedValue | string | null | 焦点锚点;焦点不在列表内时为 null。 |
disabled | boolean | |
isSelected | (value: string) => boolean | |
setValue | (next: string[]) => void | |
select | (value: string) => void | 只留这一个;加选用 toggle。 |
toggle | (value: string) => void | |
getRootProps | () => T['element'] | |
getLabelProps | () => T['element'] | |
getContentProps | () => T['element'] | |
getItemGroupProps | (props: ListboxItemGroupProps) => T['element'] | |
getItemGroupLabelProps | (props: ListboxItemGroupProps) => T['element'] | |
getItemProps | (props: ListboxItemProps) => T['element'] | |
getItemTextProps | (props: ListboxItemProps) => T['element'] | |
getItemIndicatorProps | (props: ListboxItemProps) => T['element'] |
键盘
规格出处:W3C APG
| 按键 | 生效条件 | 行为 |
|---|---|---|
Tab / Shift+Tab | focus outside the listbox | 整个列表只占一个 Tab 位:焦点进入锚点条目,无锚点时先落容器再由它转投 |
ArrowDown | focus in listbox, orientation=vertical | 焦点移到下一个可停留条目(禁用项跳过、尽头按 loop 回绕);orientation=horizontal 时改由 ArrowRight 承担,dir=rtl 再对调左右 |
ArrowUp | focus in listbox, orientation=vertical | 焦点移到上一个可停留条目(禁用项跳过、尽头按 loop 回绕);orientation=horizontal 时改由 ArrowLeft 承担,dir=rtl 再对调左右 |
Home | focus in listbox | 焦点移到首个可停留条目 |
End | focus in listbox | 焦点移到末个可停留条目 |
Enter / Space | focus on item, selectionMode 为 single 或 extended | 只选中焦点条目,替换原有选中;条目自报禁用则不认 |
Space / Enter / Ctrl+Space | focus on item, 可多选(multiple;extended 下须按住 Ctrl/Cmd) | 切换焦点条目的选中态,其余选中不动 |
Shift+ArrowDown / Shift+ArrowUp | focus in listbox, 可多选 | 焦点移到相邻条目并切换它的选中态;往回走即把刚扩进来的那个摘掉 |
Ctrl+A / Cmd+A | focus in listbox, 可多选 | 选中全部可选条目;已经全选则把它们一并取消(禁用但已选中的不动) |
单个可打印字符 | focus in listbox, typeahead 未关 | 连打检索把焦点移到首字母匹配的条目,不改选中值 |
