列表框
查看源代码列表框显示选项列表并允许用户选择其中一个或多个。
演示
import { Listbox, ListboxContent, ListboxList } from "@resolid/react-ui";
export default function App() {
const collection = [
{
label: "Fruits",
children: [
{ value: "apple", label: "Apple" },
{ value: "banana", label: "Banana" },
{ value: "blueberry", label: "Blueberry" },
{ value: "grapes", label: "Grapes" },
{ value: "pineapple", label: "Pineapple" },
],
},
{
label: "Vegetables",
children: [
{ value: "aubergine", label: "Aubergine" },
{ value: "broccoli", label: "Broccoli" },
{ value: "carrot", label: "Carrot" },
{ value: "courgette", label: "Courgette", disabled: true },
{ value: "leek", label: "Leek" },
],
},
];
return (
<Listbox name={"listbox"} className={"min-w-60"} collection={collection}>
<ListboxContent className={"max-h-60 p-1"}>
<ListboxList />
</ListboxContent>
</Listbox>
);
}
用法
import {
Listbox,
ListboxFilter,
ListboxContent,
ListboxVirtualizer,
ListboxList,
} from "@resolid/react-ui";
Listbox
: 列表框的根容器。ListboxFilter
: 列表框的筛选框ListboxContent
: 列表框要渲染的内容。ListboxVirtualizer
: 实现列表虚拟化。ListboxList
: 列表框的项目列表。
<Listbox>
<ListboxFilter />
<ListboxContent>
<ListboxVirtualizer>
<ListboxList />
</ListboxVirtualizer>
</ListboxContent>
</Listbox>
特点
- 可以是受控的,也可以是不受控的。
- 支持项目、标签、项目组。
- 焦点得到全面管理。
- 完整的键盘导航。
- 支持虚拟化
举例
多选
使用 multiple
属性实现多选
import { Listbox, ListboxContent, ListboxList } from "@resolid/react-ui";
export default function App() {
const collection = [
{
label: "Fruits",
children: [
{ value: "apple", label: "Apple" },
{ value: "banana", label: "Banana" },
{ value: "blueberry", label: "Blueberry" },
{ value: "grapes", label: "Grapes" },
{ value: "pineapple", label: "Pineapple" },
],
},
{
label: "Vegetables",
children: [
{ value: "aubergine", label: "Aubergine" },
{ value: "broccoli", label: "Broccoli" },
{ value: "carrot", label: "Carrot" },
{ value: "courgette", label: "Courgette", disabled: true },
{ value: "leek", label: "Leek" },
],
},
];
return (
<Listbox
multiple
defaultValue={["broccoli", "carrot"]}
name={"listbox"}
className={"min-w-60"}
collection={collection}
>
<ListboxContent className={"max-h-60 p-1"}>
<ListboxList />
</ListboxContent>
</Listbox>
);
}
筛选
使用 ListboxFilter
组件可以实现项目筛选
import {
Listbox,
ListboxFilter,
ListboxContent,
ListboxVirtualizer,
ListboxList,
} from "@resolid/react-ui";
export default function App() {
const collection = [
{
label: "Fruits",
children: [
{ value: "apple", label: "Apple" },
{ value: "banana", label: "Banana" },
{ value: "blueberry", label: "Blueberry" },
{ value: "grapes", label: "Grapes" },
{ value: "pineapple", label: "Pineapple" },
],
},
{
label: "Vegetables",
children: [
{ value: "aubergine", label: "Aubergine" },
{ value: "broccoli", label: "Broccoli" },
{ value: "carrot", label: "Carrot" },
{ value: "courgette", label: "Courgette", disabled: true },
{ value: "leek", label: "Leek" },
],
},
];
const virtualCollection = Array.from({ length: 1000 }, (_, i) => ({
value: i + 1,
label: `Item ${i + 1}`,
}));
return (
<div className={"flex flex-row gap-5"}>
<Listbox name={"testSingleNormal"} className={"min-w-60"} collection={collection}>
<div className={"border-bd-subtle border-b p-2"}>
<ListboxFilter size={"sm"} />
</div>
<ListboxContent className={"max-h-60 p-1"}>
<ListboxList />
</ListboxContent>
</Listbox>
<Listbox
name={"testMultipleVirtual"}
multiple
required
className={"min-w-60"}
collection={virtualCollection}
>
<div className={"border-bd-subtle border-b p-2"}>
<ListboxFilter size={"sm"} />
</div>
<ListboxContent className={"max-h-60 px-1"}>
<ListboxVirtualizer>
<ListboxList />
</ListboxVirtualizer>
</ListboxContent>
</Listbox>
</div>
);
}
虚拟化
使用 ListboxVirtualizer
组件可以实现虚拟化
import { Listbox, ListboxContent, ListboxVirtualizer, ListboxList } from "@resolid/react-ui";
export default function App() {
const collection = Array.from({ length: 1000 }, (_, i) => ({
value: i + 1,
label: `Item ${i + 1}`,
}));
const groupCollection = Array.from({ length: Math.ceil(collection.length / 20) }, (_, i) => ({
label: `Group ${i + 1}`,
children: collection.slice(i * 20, (i + 1) * 20),
}));
return (
<div className={"flex flex-row gap-5"}>
<Listbox defaultValue={201} className={"min-w-60"} collection={collection}>
<ListboxContent className={"max-h-60 px-1"}>
<ListboxVirtualizer>
<ListboxList />
</ListboxVirtualizer>
</ListboxContent>
</Listbox>
<Listbox
multiple
defaultValue={[201, 203]}
className={"min-w-60"}
collection={groupCollection}
>
<ListboxContent className={"max-h-60 px-1"}>
<ListboxVirtualizer>
<ListboxList />
</ListboxVirtualizer>
</ListboxContent>
</Listbox>
</div>
);
}
自定义渲染
使用 renderItem
属性实现自定义渲染
import { Listbox, ListboxContent, ListboxList } from "@resolid/react-ui";
import { BrowserIcon } from "~/components/browser-icon";
export default function App() {
const collection = [
{
value: "chrome",
label: "Chrome",
description: "Google Chrome 是一款快速、易于使用且安全的网络浏览器。",
},
{
value: "firefox",
label: "Firefox",
description: "Firefox 是一款快速、轻量、注重隐私的浏览器,全平台可用。",
},
{
value: "microsoft-edge",
label: "Microsoft Edge",
description: "Microsoft Edge 是 AI 驱动的浏览器。更智能的浏览方式。",
},
{
value: "safari",
label: "Safari",
description: "Safari 是在所有 Apple 设备上体验互联网的最佳方式。",
},
{
value: "opera",
label: "Opera",
description: "比默认浏览器更快、更安全、更智能。 功能齐全,可保护隐私、安全等。",
},
];
return (
<Listbox
name={"listbox"}
className={"max-w-96"}
collection={collection}
renderItem={(item, { selected }) => {
return (
<div className={"flex items-center gap-2"}>
<div className={"w-12 flex-1"}>
<BrowserIcon size={"2em"} name={item.value} />
</div>
<div className={"flex flex-col gap-1"}>
<div>{item.label}</div>
<div className={`text-sm ${!selected ? "text-fg-subtle" : ""}`}>
{item.description}
</div>
</div>
</div>
);
}}
>
<ListboxContent className={"p-1"}>
<ListboxList />
</ListboxContent>
</Listbox>
);
}
属性
Listbox
属性 | 类型 | 默认值 | 必须 | |
---|---|---|---|---|
属性 multiple | 是否多选 | 类型boolean | 默认值false | 必须false |
属性 collection | 项目的集合 | 类型T[] | 默认值- | 必须true |
属性 valueKey | 自定义 `value` 字段名 | 类型string | 默认值"value" | 必须false |
属性 labelKey | 自定义 `label` 字段名 | 类型string | 默认值"label" | 必须false |
属性 disabledKey | 自定义 `disabled` 字段名 | 类型string | 默认值"disabled" | 必须false |
属性 childrenKey | 自定义 `children` 字段名 | 类型string | 默认值"children" | 必须false |
属性 searchFilter | 自定义过滤函数 | 类型(keyword: string, item: T) => boolean | 默认值- | 必须false |
属性 renderItem | 自定义项目渲染 | 类型(item: T, status: { active: boolean; selected: boolean; }) => ReactNode | 默认值- | 必须false |
属性 renderGroupLabel | 自定义组标签渲染 | 类型(group: T) => ReactNode | 默认值- | 必须false |
属性 size | 大小 | 类型"xs" | "sm" | "md" | "lg" | "xl" | 默认值"md" | 必须false |
属性 value | 受控值 | 类型string | number | (string | number)[] | null | 默认值- | 必须false |
属性 defaultValue | 默认值 | 类型string | number | (string | number)[] | null | 默认值null | [] | 必须false |
属性 onChange | onChange 回调 | 类型((value: string | number | (string | number)[] | null) => void) | 默认值- | 必须false |
属性 name | 字段的名称, 提交表单时使用 | 类型string | 默认值- | 必须false |
属性 disabled | 是否禁用 | 类型boolean | 默认值false | 必须false |
属性 required | 是否必需 | 类型boolean | 默认值false | 必须false |
属性 readOnly | 是否只读 | 类型boolean | 默认值false | 必须false |
属性 invalid | 是否无效 | 类型boolean | 默认值false | 必须false |
ListboxFilter
属性 | 类型 | 默认值 | 必须 | |
---|---|---|---|---|
属性 size | 大小 | 类型"xs" | "sm" | "md" | "lg" | "xl" | 默认值"md" | 必须false |
属性 placeholder | 占位符文本 | 类型string | 默认值- | 必须false |
属性 prefix | 前置元素 | 类型ReactNode | 默认值- | 必须false |
属性 prefixWidth | 前置元素宽度 | 类型number | 默认值- | 必须false |
属性 value | 可控值 | 类型string | number | 默认值- | 必须false |
属性 defaultValue | 默认值 | 类型string | number | 默认值"" | 必须false |
属性 onChange | onChange 回调 | 类型((value: string | number) => void) | 默认值- | 必须false |
属性 disabled | 是否禁用 | 类型boolean | 默认值false | 必须false |
ListboxVirtualizer
属性 | 类型 | 默认值 | 必须 | |
---|---|---|---|---|
属性 itemHeight | 项目的高度(以像素为单位) | 类型number | 默认值- | 必须false |
属性 groupLabelHeight | 分组标签的高度(以像素为单位) | 类型number | 默认值- | 必须false |
属性 overscan | 在可见区域上方和下方渲染的项目数 | 类型number | 默认值3 | 必须false |
属性 paddingStart | 应用于虚拟器开始处的填充(以像素为单位) | 类型number | 默认值4 | 必须false |
属性 paddingEnd | 应用于虚拟器末尾的填充(以像素为单位) | 类型number | 默认值4 | 必须false |
属性 scrollPaddingStart | 滚动到元素时应用于虚拟器开始处的填充(以像素为单位) | 类型number | 默认值4 | 必须false |
属性 scrollPaddingEnd | 滚动到元素时应用于虚拟器末尾的填充(以像素为单位) | 类型number | 默认值4 | 必须false |
属性 gap | 虚拟化列表中项目之间的间距 | 类型number | 默认值- | 必须false |
属性 useAnimationFrameWithResizeObserver | 将 ResizeObserver 封装在 requestAnimationFrame 中,实现更顺畅的更新并减少布局抖动 | 类型boolean | 默认值- | 必须false |