跳至内容

列表框

一个允许用户在选中和未选中之间切换的控件。
水果
苹果
香蕉
蓝莓
葡萄
菠萝
蔬菜
茄子
西兰花
胡萝卜
西葫芦
韭葱
vue
<script setup lang="ts">
import { Icon } from '@iconify/vue'
import { ListboxContent, ListboxGroup, ListboxGroupLabel, ListboxItem, ListboxItemIndicator, ListboxRoot } from 'radix-vue'

const fruits = ['Apple', 'Banana', 'Blueberry', 'Grapes', 'Pineapple']
const vegetables = ['Aubergine', 'Broccoli', 'Carrot', 'Courgette', 'Leek']
</script>

<template>
  <ListboxRoot class=" flex flex-col rounded-lg border bg-white text-green9 mx-auto ">
    <ListboxContent class="p-[5px] w-48 h-72 overflow-auto">
      <ListboxGroup>
        <ListboxGroupLabel class="px-[25px] text-xs leading-[25px] text-mauve11">
          Fruits
        </ListboxGroupLabel>
        <ListboxItem
          v-for="i in fruits"
          :key="i"
          :value="i"
          class="w-full flex items-center px-[25px] h-[25px] leading-none text-[13px] relative text-green9 select-none outline-none data-[highlighted]:ring-green9 data-[highlighted]:ring-1 focus:ring-green9 focus:ring-1  data-[state=checked]:bg-green9 data-[state=checked]:text-white data-[disabled]:opacity-50 rounded"
        >
          <ListboxItemIndicator
            class="absolute left-0 w-[25px] inline-flex items-center justify-center"
          >
            <Icon icon="radix-icons:check" />
          </ListboxItemIndicator>
          <span>{{ i }}</span>
        </ListboxItem>
      </ListboxGroup>

      <ListboxGroup class="mt-2">
        <ListboxGroupLabel class="px-[25px] text-xs leading-[25px] text-mauve11">
          Vegetables
        </ListboxGroupLabel>
        <ListboxItem
          v-for="i in vegetables"
          :key="i"
          :value="i"
          class="w-full flex items-center px-[25px] h-[25px] leading-none text-[13px] relative text-green9 select-none outline-none data-[highlighted]:ring-green9 data-[highlighted]:ring-1 focus:ring-green9 focus:ring-1  data-[state=checked]:bg-green9 data-[state=checked]:text-white data-[disabled]:opacity-50 rounded"
        >
          <ListboxItemIndicator
            class="absolute left-0 w-[25px] inline-flex items-center justify-center"
          >
            <Icon icon="radix-icons:check" />
          </ListboxItemIndicator>
          <span>{{ i }}</span>
        </ListboxItem>
      </ListboxGroup>
    </ListboxContent>
  </ListboxRoot>
</template>

特性

  • 可以是受控的或不受控的。
  • 支持项目、标签、项目组。
  • 焦点完全受管理。
  • 完整的键盘导航。
  • 支持从右到左方向。
  • 不同的选择行为。

安装

从命令行安装组件。

sh
$ npm add radix-vue

解剖结构

导入所有部分并将它们组合在一起。

vue
<script setup>
import { ListboxContent, ListboxFilter, ListboxGroup, ListboxGroupLabel, ListboxItem, ListboxItemIndicator, ListboxRoot, ListboxVirtualizer } from 'radix-vue'
</script>

<template>
  <ListboxRoot>
    <ListboxFilter />

    <ListboxContent>
      <ListboxItem>
        <ListboxItemIndicator />
      </ListboxItem>

      <!-- or with group -->
      <ListboxGroup>
        <ListboxGroupLabel />
        <ListboxItem>
          <ListboxItemIndicator />
        </ListboxItem>
      </ListboxGroup>

      <!-- or with virtual -->
      <ListboxVirtualizer>
        <ListboxItem>
          <ListboxItemIndicator />
        </ListboxItem>
      </ListboxVirtualizer>
    </ListboxContent>
  </ListboxRoot>
</template>

API 参考

包含列表框的所有部分。当在 form 中使用时,还会渲染一个 input,以确保事件正确传播。

属性默认值类型
as
'div'
AsTag | 组件

此组件应渲染成的元素或组件。可以被 asChild 覆盖

asChild
布尔值

将默认渲染的元素更改为作为子元素传递的元素,合并其属性和行为。

阅读我们的 组合 指南了解更多详细信息。

by
字符串 | ((a: 可接受值, b: 可接受值) => 布尔值)

使用此方法根据特定字段比较对象,或传递您自己的比较函数以完全控制对象如何比较。

defaultValue
可接受值 | 可接受值[]

列表框在初始渲染时的值。当您不需要控制列表框的状态时使用

dir
'ltr' | 'rtl'

列表框的阅读方向(如果适用)。
如果省略,则从 ConfigProvider 全局继承,或假设 LTR(从左到右)阅读模式。

disabled
布尔值

true 时,阻止用户与列表框交互

highlightOnHover
布尔值

true 时,鼠标悬停在项目上将触发突出显示

modelValue
可接受值 | 可接受值[]

列表框的受控值。可以使用 v-model 进行绑定。

multiple
布尔值

是否可以选择多个选项。

name
字符串

列表框的名称。作为名称/值对的一部分与其所属的表单一起提交。

orientation
'vertical'
'vertical' | 'horizontal'

列表框的方向。
主要是为了让箭头导航相应地进行(左右 vs. 上下)

selectionBehavior
'toggle'
'replace' | 'toggle'

在集合中如何处理多选行为。

发射有效载荷
entryFocus
[事件: CustomEvent<any>]

容器被聚焦时调用的事件处理程序。可以阻止。

highlight
[有效载荷: { ref: HTMLElement; value: 可接受值; }]

突出显示元素发生变化时的事件处理程序。

leave
[事件: 事件]

鼠标离开容器时调用的事件处理程序

update:modelValue
[值: 可接受值]

值发生变化时调用的事件处理程序。

插槽 (默认)有效载荷
modelValue
可接受值 | 可接受值[] | 未定义

当前活动值

数据属性
[data-disabled]禁用时存在

过滤器

用于执行过滤的输入元素。

属性默认值类型
as
'input'
AsTag | 组件

此组件应渲染成的元素或组件。可以被 asChild 覆盖

asChild
布尔值

将默认渲染的元素更改为作为子元素传递的元素,合并其属性和行为。

阅读我们的 组合 指南了解更多详细信息。

autoFocus
布尔值

安装时将焦点设置到元素上。

modelValue
字符串

过滤器的受控值。可以使用 v-model 进行绑定。

发射有效载荷
update:modelValue
[字符串]

值发生变化时调用的事件处理程序。

插槽 (默认)有效载荷
modelValue
字符串 | 未定义

当前输入值

数据属性
[data-disabled]禁用时存在

内容

包含所有列表框组和项目。

属性默认值类型
as
'div'
AsTag | 组件

此组件应渲染成的元素或组件。可以被 asChild 覆盖

asChild
布尔值

将默认渲染的元素更改为作为子元素传递的元素,合并其属性和行为。

阅读我们的 组合 指南了解更多详细信息。

项目

项目组件。

属性默认值类型
as
'div'
AsTag | 组件

此组件应渲染成的元素或组件。可以被 asChild 覆盖

asChild
布尔值

将默认渲染的元素更改为作为子元素传递的元素,合并其属性和行为。

阅读我们的 组合 指南了解更多详细信息。

disabled
布尔值

true 时,阻止用户与项目交互。

value*
可接受值

使用 name 提交时作为数据提供的值。

发射有效载荷
select
[事件: SelectEvent<可接受值>]

选择项目时调用的事件处理程序。
可以通过调用 event.preventDefault 阻止它。

数据属性
[data-state]"checked" | "unchecked"
[data-highlighted]突出显示时存在
[data-disabled]禁用时存在

项目指示器

当项目被选中时渲染。您可以直接设置此元素的样式,也可以将其用作包装器以放入图标,或者两者兼而有之。

属性默认值类型
as
'span'
AsTag | 组件

此组件应渲染成的元素或组件。可以被 asChild 覆盖

asChild
布尔值

将默认渲染的元素更改为作为子元素传递的元素,合并其属性和行为。

阅读我们的 组合 指南了解更多详细信息。

用于对多个项目进行分组。与 ListboxGroupLabel 结合使用,以确保通过自动标签提供良好的可访问性。

属性默认值类型
as
'div'
AsTag | 组件

此组件应渲染成的元素或组件。可以被 asChild 覆盖

asChild
布尔值

将默认渲染的元素更改为作为子元素传递的元素,合并其属性和行为。

阅读我们的 组合 指南了解更多详细信息。

组标签

用于渲染组的标签。它不能使用箭头键进行聚焦。

属性默认值类型
as
'div'
AsTag | 组件

此组件应渲染成的元素或组件。可以被 asChild 覆盖

asChild
布尔值

将默认渲染的元素更改为作为子元素传递的元素,合并其属性和行为。

阅读我们的 组合 指南了解更多详细信息。

for
字符串

虚拟化器

用于实现列表虚拟化的虚拟容器。

属性默认值类型
estimateSize
数字

每个项目的估计大小(以像素为单位)

options*
可接受值[]

项目列表

textContent
((option: 可接受值) => 字符串)

每个项目的文本内容,用于实现提前输入功能

插槽 (默认)有效载荷
option
字符串 | 数字 | false | true | Record<字符串, 任何>

示例

将对象绑定为值

与只能提供字符串作为值的原生 HTML 表单控件不同,radix-vue 还支持绑定复杂对象。

vue
<script setup lang="ts">
import { ref } from 'vue'
import { ListboxContent, ListboxFilter, ListboxItem, ListboxRoot } from 'radix-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 组件允许您选择多个值。您可以通过提供一个值数组而不是单个值来启用此功能。

vue
<script setup lang="ts">
import { ref } from 'vue'
import { ListboxRoot } from 'radix-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>

自定义过滤

vue
<script setup lang="ts">
import { ref } from 'vue'
import { ListboxContent, ListboxFilter, ListboxItem, ListboxRoot } from 'radix-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 filteredPeople = computed(() =>
  searchTerm.value === ''
    ? people
    : people.filter((person) => {
      return person.name.toLowerCase().includes(searchTerm.value.toLowerCase())
    })
)
</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>

虚拟列表

渲染一个很长的项目列表会降低应用程序的速度,因此使用虚拟化会显着提高性能。

vue
<script setup lang="ts">
import { ref } from 'vue'
import { ListboxContent, ListboxFilter, ListboxItem, ListboxRoot, ListboxVirtualizer } from 'radix-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' },
  // and a lot more
]
</script>

<template>
  <ListboxRoot>
    <ListboxContent>
      <!-- checkout https://radix-vue.com/components/listbox.html#virtualizer -->
      <ListboxVirtualizer
        v-slot="{ option }"
        :options="people"
        :text-content="(opt) => opt.name"
      >
        <ListboxItem :value="option">
          {{ person.name }}
        </ListboxItem>
      </ListboxVirtualizer>
    </ListboxContent>
  </ListboxRoot>
</template>

无障碍性

符合 Listbox WAI-ARIA 设计模式.

键盘交互

描述
Enter
当在 ListboxItem 上突出显示时,选择聚焦的项目。
ArrowDown
当焦点在 ListboxItem 上时,将焦点移动到下一个项目。
ArrowUp
当焦点在 ListboxItem 上时,将焦点移动到上一个项目。
Home
将焦点和突出显示移动到第一个项目。
End
将焦点和突出显示移动到最后一个项目。
Ctrl/Cmd + A
选择所有项目。