选择列表框
功能特性
- 可被控制或非受控。
- 支持项目、标签、项目组。
- 焦点管理完备。
- 完整的键盘导航支持。
- 支持从右到左方向。
- 不同的选择行为。
安装
通过命令行安装该组件。
$ npm add reka-ui结构构成
导入所有部分并将它们组合在一起。
<script setup>
import { ListboxContent, ListboxFilter, ListboxGroup, ListboxGroupLabel, ListboxItem, ListboxItemIndicator, ListboxRoot, ListboxVirtualizer } from 'reka-ui'
</script>
<template>
<ListboxRoot>
<ListboxFilter />
<ListboxContent>
<ListboxItem>
<ListboxItemIndicator />
</ListboxItem>
<!-- 或使用分组 -->
<ListboxGroup>
<ListboxGroupLabel />
<ListboxItem>
<ListboxItemIndicator />
</ListboxItem>
</ListboxGroup>
<!-- 或使用虚拟化 -->
<ListboxVirtualizer>
<ListboxItem>
<ListboxItemIndicator />
</ListboxItem>
</ListboxVirtualizer>
</ListboxContent>
</ListboxRoot>
</template>API 参考
Root
包含选择列表框的所有部分。在 form 内使用时还会渲染一个 input 元素,以确保事件能正确传播。
| Prop | Default | Type |
|---|---|---|
as | 'div' | AsTag | ComponentThe element or component this component should render as. Can be overwritten by |
asChild | booleanChange the default rendered element for the one passed as a child, merging their props and behavior. Read our Composition guide for more details. | |
by | string | ((a: AcceptableValue, b: AcceptableValue) => boolean)Use this to compare objects by a particular field, or pass your own comparison function for complete control over how objects are compared. | |
defaultValue | AcceptableValue | AcceptableValue[]The value of the listbox when initially rendered. Use when you do not need to control the state of the Listbox | |
dir | 'ltr' | 'rtl'The reading direction of the listbox when applicable. | |
disabled | booleanWhen | |
highlightOnHover | booleanWhen | |
modelValue | AcceptableValue | AcceptableValue[]The controlled value of the listbox. Can be binded with with | |
multiple | booleanWhether multiple options can be selected or not. | |
name | stringThe name of the field. Submitted with its owning form as part of a name/value pair. | |
orientation | 'vertical' | 'vertical' | 'horizontal'The orientation of the listbox. |
required | booleanWhen | |
selectionBehavior | 'toggle' | 'replace' | 'toggle'How multiple selection should behave in the collection. |
| Emit | Payload |
|---|---|
entryFocus | [event: CustomEvent<any>]Event handler called when container is being focused. Can be prevented. |
highlight | [payload: { ref: HTMLElement; value: AcceptableValue; }]Event handler when highlighted element changes. |
leave | [event: Event]Event handler called when the mouse leave the container |
update:modelValue | [value: AcceptableValue]Event handler called when the value changes. |
| Slots (default) | Payload |
|---|---|
modelValue | AcceptableValue | AcceptableValue[] | undefinedCurrent active value |
| Data Attribute | Value |
|---|---|
[data-disabled] | 禁用时存在 |
Filter
用于执行筛选的输入元素。
| Prop | Default | Type |
|---|---|---|
as | 'input' | AsTag | ComponentThe element or component this component should render as. Can be overwritten by |
asChild | booleanChange the default rendered element for the one passed as a child, merging their props and behavior. Read our Composition guide for more details. | |
autoFocus | booleanFocus on element when mounted. | |
disabled | booleanWhen | |
modelValue | stringThe controlled value of the filter. Can be binded with with v-model. |
| Emit | Payload |
|---|---|
update:modelValue | [string]Event handler called when the value changes. |
| Slots (default) | Payload |
|---|---|
modelValue | string | undefinedCurrent input values |
| Data Attribute | Value |
|---|---|
[data-disabled] | 禁用时存在 |
Content
包含所有选择列表框组和项目。
| Prop | Default | Type |
|---|---|---|
as | 'div' | AsTag | ComponentThe element or component this component should render as. Can be overwritten by |
asChild | booleanChange the default rendered element for the one passed as a child, merging their props and behavior. Read our Composition guide for more details. |
Item
项目组件。
| Prop | Default | Type |
|---|---|---|
as | 'div' | AsTag | ComponentThe element or component this component should render as. Can be overwritten by |
asChild | booleanChange the default rendered element for the one passed as a child, merging their props and behavior. Read our Composition guide for more details. | |
disabled | booleanWhen | |
value* | AcceptableValueThe value given as data when submitted with a |
| Emit | Payload |
|---|---|
select | [event: SelectEvent<AcceptableValue>]Event handler called when the selecting item. |
| Data Attribute | Value |
|---|---|
[data-state] | "checked" | "unchecked" |
[data-highlighted] | 高亮时存在 |
[data-disabled] | 禁用时存在 |
ItemIndicator
在项目被选中时渲染。您可以直接为此元素设置样式,或将其用作包装器来放置图标,或两者兼有。
| Prop | Default | Type |
|---|---|---|
as | 'span' | AsTag | ComponentThe element or component this component should render as. Can be overwritten by |
asChild | booleanChange the default rendered element for the one passed as a child, merging their props and behavior. Read our Composition guide for more details. |
Group
用于对多个项目进行分组。与 ListboxGroupLabel 结合使用,通过自动标签化确保良好的可访问性。
| Prop | Default | Type |
|---|---|---|
as | 'div' | AsTag | ComponentThe element or component this component should render as. Can be overwritten by |
asChild | booleanChange the default rendered element for the one passed as a child, merging their props and behavior. Read our Composition guide for more details. |
GroupLabel
用于渲染组的标签。使用方向键无法使其获得焦点。
| Prop | Default | Type |
|---|---|---|
as | 'div' | AsTag | ComponentThe element or component this component should render as. Can be overwritten by |
asChild | booleanChange the default rendered element for the one passed as a child, merging their props and behavior. Read our Composition guide for more details. | |
for | string |
Virtualizer
虚拟容器,用于实现列表虚拟化。
| Prop | Default | Type |
|---|---|---|
estimateSize | numberEstimated size (in px) of each item | |
options* | AcceptableValue[]List of items | |
overscan | numberNumber of items rendered outside the visible area | |
textContent | ((option: AcceptableValue) => string)Text content for each item to achieve type-ahead feature |
| Slots (default) | Payload |
|---|---|
option | null | string | number | bigint | Record<string, any> |
virtualizer | Virtualizer<HTMLElement, Element> |
virtualItem | VirtualItem |
示例
绑定对象作为值
与仅允许提供字符串作为值的原生 HTML 表单控件不同,reka-ui 也支持绑定复杂对象。
<script setup lang="ts">
import { ListboxContent, ListboxFilter, ListboxItem, ListboxRoot } from 'reka-ui'
import { ref } from 'vue'
const people = [
{ id: 1, name: 'Durward Reynolds' },
{ id: 2, name: 'Kenton Towne' },
{ id: 3, name: 'Therese Wunsch' },
{ id: 4, name: 'Benedict Kessler' },
{ id: 5, name: 'Katelyn Rohan' },
]
const selectedPeople = ref(people[0])
</script>
<template>
<ListboxRoot v-model="selectedPeople">
<ListboxContent>
<ListboxItem
v-for="person in people"
:key="person.id"
:value="person"
:disabled="person.unavailable"
>
{{ person.name }}
</ListboxItem>
</ListboxContent>
</ListboxRoot>
</template>选择多个值
Listbox 组件允许您选择多个值。您可以通过提供一个值数组而非单个值来启用此功能。
<script setup lang="ts">
import { ListboxRoot } from 'reka-ui'
import { ref } from 'vue'
const people = [
{ id: 1, name: 'Durward Reynolds' },
{ id: 2, name: 'Kenton Towne' },
{ id: 3, name: 'Therese Wunsch' },
{ id: 4, name: 'Benedict Kessler' },
{ id: 5, name: 'Katelyn Rohan' },
]
const selectedPeople = ref([people[0], people[1]])
</script>
<template>
<ListboxRoot
v-model="selectedPeople"
multiple
>
...
</ListboxRoot>
</template>自定义筛选
<script setup lang="ts">
import { ListboxContent, ListboxFilter, ListboxItem, ListboxRoot, useFilter } from 'reka-ui'
import { ref } from 'vue'
const people = [
{ id: 1, name: 'Durward Reynolds' },
{ id: 2, name: 'Kenton Towne' },
{ id: 3, name: 'Therese Wunsch' },
{ id: 4, name: 'Benedict Kessler' },
{ id: 5, name: 'Katelyn Rohan' },
]
const selectedPeople = ref(people[0])
const searchTerm = ref('')
const { startsWith } = useFilter({ sensitivity: 'base' })
const filteredPeople = computed(() => people.filter(p => startsWith(p.name, searchTerm.value)))
</script>
<template>
<ListboxRoot v-model="selectedPeople">
<ListboxFilter v-model="searchTerm" />
<ListboxContent>
<ListboxItem
v-for="person in filteredPeople"
:key="person.id"
:value="person"
>
{{ person.name }}
</ListboxItem>
</ListboxContent>
</ListboxRoot>
</template>虚拟列表
渲染长列表可能会降低应用速度,因此使用虚拟化将显著提高性能。
有关虚拟化的更多常规信息,请参阅 虚拟化指南。
<script setup lang="ts">
import { ListboxContent, ListboxFilter, ListboxItem, ListboxRoot, ListboxVirtualizer } from 'reka-ui'
import { ref } from 'vue'
const people = [
{ id: 1, name: 'Durward Reynolds' },
{ id: 2, name: 'Kenton Towne' },
{ id: 3, name: 'Therese Wunsch' },
{ id: 4, name: 'Benedict Kessler' },
{ id: 5, name: 'Katelyn Rohan' },
// 以及更多
]
</script>
<template>
<ListboxRoot>
<ListboxContent>
<ListboxVirtualizer
v-slot="{ option }"
:options="people"
:text-content="(opt) => opt.name"
>
<ListboxItem :value="option">
{{ person.name }}
</ListboxItem>
</ListboxVirtualizer>
</ListboxContent>
</ListboxRoot>
</template>可访问性
键盘交互
| Key | Description |
|---|---|
Enter | 当高亮在 ListboxItem 上时,选中获得焦点的项目。 |
ArrowDown | 当焦点在 ListboxItem 上时,将焦点移动到下一个项目。 |
ArrowUp | 当焦点在 ListboxItem 上时,将焦点移动到上一个项目。 |
Home | 将焦点和高亮移动到第一个项目。 |
End | 将焦点和高亮移动到最后一个项目。 |
Ctrl/Cmd + A | 选择所有项目。 |
