Cascader 级联选择
用于位置或类别等层级数据的级联选择框。
import { Cascader } from 'asterui'基本用法
简单的层级选择。
Select location
import { Cascader } from 'asterui'
function App() {
const options = [
{
value: 'usa',
label: 'United States',
children: [
{
value: 'ca',
label: 'California',
children: [
{ value: 'sf', label: 'San Francisco' },
{ value: 'la', label: 'Los Angeles' },
],
},
{
value: 'ny',
label: 'New York',
children: [
{ value: 'nyc', label: 'New York City' },
{ value: 'buf', label: 'Buffalo' },
],
},
],
},
]
return (
<Cascader options={options} placeholder="Select location" />
)
}
export default App 悬停展开
悬停时展开子菜单。
Select category
import { Cascader } from 'asterui'
function App() {
const options = [
{
value: 'electronics',
label: 'Electronics',
children: [
{
value: 'phones',
label: 'Phones',
children: [
{ value: 'iphone', label: 'iPhone' },
{ value: 'android', label: 'Android' },
],
},
{
value: 'computers',
label: 'Computers',
children: [
{ value: 'laptop', label: 'Laptop' },
{ value: 'desktop', label: 'Desktop' },
],
},
],
},
]
return (
<Cascader options={options} expandTrigger="hover" placeholder="Select category" />
)
}
export default App 尺寸
不同的级联选择器尺寸。
Extra small
Small
Medium
Large
import { Cascader } from 'asterui'
function App() {
const options = [
{ value: 'opt1', label: 'Option 1' },
{ value: 'opt2', label: 'Option 2' },
]
return (
<div className="flex flex-col gap-2">
<Cascader size="xs" options={options} placeholder="Extra small" />
<Cascader size="sm" options={options} placeholder="Small" />
<Cascader size="md" options={options} placeholder="Medium" />
<Cascader size="lg" options={options} placeholder="Large" />
</div>
)
}
export default App 禁用状态
禁用的级联选择器状态。
Option 1
import { Cascader } from 'asterui'
function App() {
const options = [
{ value: 'opt1', label: 'Option 1' },
{ value: 'opt2', label: 'Option 2' },
]
return (
<Cascader options={options} disabled value={['opt1']} />
)
}
export default App 搜索
启用搜索/过滤功能。
Search locations
import { Cascader } from 'asterui'
function App() {
const options = [
{
value: 'usa',
label: 'United States',
children: [
{
value: 'ca',
label: 'California',
children: [
{ value: 'sf', label: 'San Francisco' },
{ value: 'la', label: 'Los Angeles' },
],
},
],
},
]
return (
<Cascader options={options} showSearch placeholder="Search locations" />
)
}
export default App 选择即改变
允许选择任何级别,而不仅是叶子节点。
Select any level
Selected: None
import { Cascader } from 'asterui'
import { useState } from 'react'
function App() {
const [value, setValue] = useState<string[]>([])
const options = [
{
value: 'usa',
label: 'United States',
children: [
{ value: 'ca', label: 'California' },
{ value: 'ny', label: 'New York' },
],
},
]
return (
<div>
<Cascader
options={options}
changeOnSelect
value={value}
onChange={setValue}
placeholder="Select any level"
/>
<p className="mt-2 text-sm">Selected: {value.join(' / ') || 'None'}</p>
</div>
)
}
export default App 异步加载
展开时动态加载选项。
Load on expand
import { Cascader } from 'asterui'
import { useState } from 'react'
function App() {
const [options, setOptions] = useState<CascaderOption[]>([
{ value: 'region1', label: 'Region 1' },
{ value: 'region2', label: 'Region 2' },
])
const loadData = async (selectedOptions: CascaderOption[]) => {
const targetOption = selectedOptions[selectedOptions.length - 1]
await new Promise(resolve => setTimeout(resolve, 1000))
setOptions(prev => {
const update = (opts: CascaderOption[]): CascaderOption[] =>
opts.map(opt =>
opt.value === targetOption.value
? {
...opt,
children: [
{ value: `${opt.value}-1`, label: 'Child 1', isLeaf: true },
{ value: `${opt.value}-2`, label: 'Child 2', isLeaf: true },
],
}
: { ...opt, children: opt.children ? update(opt.children) : undefined }
)
return update(prev)
})
}
return (
<Cascader options={options} loadData={loadData} placeholder="Load on expand" />
)
}
export default App 验证状态
显示错误或警告验证状态。
Error state
Warning state
import { Cascader } from 'asterui'
function App() {
const options = [
{ value: 'opt1', label: 'Option 1' },
{ value: 'opt2', label: 'Option 2' },
]
return (
<div className="flex flex-col gap-2">
<Cascader options={options} status="error" placeholder="Error state" />
<Cascader options={options} status="warning" placeholder="Warning state" />
</div>
)
}
export default App 多选
选择多个叶子值。
Select multiple
import { Cascader } from 'asterui'
function App() {
const options = [
{
value: 'fruits',
label: 'Fruits',
children: [
{ value: 'apple', label: 'Apple' },
{ value: 'banana', label: 'Banana' },
],
},
{
value: 'vegetables',
label: 'Vegetables',
children: [
{ value: 'carrot', label: 'Carrot' },
{ value: 'lettuce', label: 'Lettuce' },
],
},
]
return (
<Cascader options={options} multiple placeholder="Select multiple" />
)
}
export default App Cascader
Section titled “Cascader”| 属性 | 描述 | 类型 | 默认值 |
|---|---|---|---|
options | 层级选项数据 | CascaderOption[] | [] |
value | 受控的选择值路径 | string[] | - |
defaultValue | 默认选择值(非受控) | string[] | [] |
onChange | 选择改变时的回调函数 | (value: string[], selectedOptions: CascaderOption[]) => void | - |
placeholder | 输入占位符文本 | string | '请选择' |
disabled | 禁用级联选择器 | boolean | false |
allowClear | 显示清除按钮 | boolean | true |
expandTrigger | 如何展开子菜单 | 'click' | 'hover' | 'click' |
changeOnSelect | 允许选择任何级别,而不仅是叶子 | boolean | false |
displayRender | 自定义显示渲染函数 | (labels: ReactNode[], selectedOptions: CascaderOption[]) => ReactNode | - |
size | 输入框大小 | 'xs' | 'sm' | 'md' | 'lg' | 'md' |
color | 焦点环颜色 | 'primary' | 'secondary' | 'accent' | 'info' | 'success' | 'warning' | 'error' | - |
status | 验证状态 | 'error' | 'warning' | - |
showSearch | 启用搜索功能 | boolean | { filter?, render?, matchInputWidth? } | false |
notFoundContent | 无搜索结果时的内容 | ReactNode | '未找到结果' |
loadData | 异步数据加载函数 | (selectedOptions: CascaderOption[]) => Promise<void> | - |
fieldNames | 数据映射的自定义字段名 | { label?: string; value?: string; children?: string } | - |
open | 受控的下拉框打开状态 | boolean | - |
onDropdownVisibleChange | 下拉框可见性改变时的回调函数 | (open: boolean) => void | - |
popupClassName | 下拉框的类名 | string | - |
dropdownRender | 自定义下拉框包装渲染 | (menu: ReactNode) => ReactNode | - |
multiple | 启用多选模式 | boolean | false |
maxTagCount | 多选模式下显示的最大标签数 | number | 'responsive' | - |
className | 额外的 CSS 类名 | string | - |
CascaderOption
Section titled “CascaderOption”| 属性 | 描述 | 类型 | 默认值 |
|---|---|---|---|
value | 唯一标识符 | string | - |
label | 显示标签 | ReactNode | - |
children | 子选项 | CascaderOption[] | - |
disabled | 禁用此选项 | boolean | false |
isLeaf | 强制作为叶子节点(不展开,不异步加载) | boolean | - |
Cascader 组件遵循 WAI-ARIA combobox 模式:
- 在触发器上使用
role="combobox",带有aria-expanded、aria-haspopup aria-activedescendant为屏幕阅读器跟踪聚焦的选项aria-selected指示选项的选中状态aria-disabled指示禁用状态- 清除按钮有
aria-label="清除选择"
| 按键 | 操作 |
|---|---|
| 下 | 打开下拉框或移动到下一个选项 |
| 上 | 移动到上一个选项 |
| 右 | 移动到下一列(展开) |
| 左 | 移动到上一列 |
| 回车 | 选择聚焦的选项或打开下拉框 |
| 空格 | 切换下拉框(非搜索时) |
| Esc | 关闭下拉框 |
| Home | 移动到第一个选项 |
| End | 移动到最后一个选项 |
组件包含用于测试的数据属性:
- 根容器上的
data-testid="cascader" - 下拉框上的
data-testid="cascader-dropdown" - 每个选项上的
data-testid="cascader-option-{value}" - 清除按钮上的
data-testid="cascader-clear" - 根上的
data-state="open|closed"指示下拉框状态 - 选项上的
data-state="selected|hovered"指示状态 - 选项上的
data-value="{value}"提供值