- 前端
- UI组件
【免费下载链接】rsuite
🧱 A suite of React components .
级联选择器(Cascader)是 rsuite 中用于「对有层级关系的数据进行单项选择」的核心组件,它把树形结构数据以多列联动的形式呈现:选中上一级节点后,下一列随之刷新。本文以 Cascader 官方文档 为骨架,完整覆盖其导入方式、10 个核心示例(外观、尺寸、异步加载、自定义渲染、受控等)、响应式行为、可访问性规范与全部 Props,并结合仓库源码(src/Cascader、src/CascadeTree)剖析其底层实现,帮助你从「会用」进阶到「用得明白」。
Cascader 是什么
Cascader组件将「层级结构」的数据源渲染为一个分列的级联列表,用户沿路径逐级选择,最终得到一个叶子节点值。它适合省市县联动、组织架构选择、商品类目选择等典型场景。
- 数据源是带
children的树形数组,结构与 Option 类型 对应; - 组件出口位于 src/Cascader/index.tsx,对外导出
Cascader及CascaderProps类型; - 其核心视图(多列联动树、搜索视图)由
src/Cascader/Cascader.tsx组合 TreeView 与 SearchView 实现,这套级联树逻辑与MultiCascader共享。
快速上手:导入与基础用法
从rsuite包中直接导入组件:
import { Cascader } from 'rsuite';官方基础示例(来源:basic.md)使用mockTreeData生成三层树数据,并对比了默认(可搜索)与searchable={false}两种形态:
import { Cascader, VStack } from 'rsuite'; import { mockTreeData } from './mock'; const data = mockTreeData({ limits: [3, 3, 4], labels: (layer, value, faker) => { const methodName = ['jobArea', 'jobType', 'firstName']; return faker.person[methodName[layer]](); } }); const App = () => { return ( <VStack> <Cascader data={data} w={224} /> <Cascader data={data} searchable={false} w={224} placeholder="Select without search" /> </VStack> ); }; ReactDOM.render(<App />, document.getElementById('root'));要点说明:
data是 Cascader 唯一必填(标记*)的属性;mockTreeData是文档站用于演示的造数工具,真实定义见 docs/utils/mock.ts;limits: [3, 3, 4]表示三层分别有 3、3、4 个子节点;- 默认开启搜索(
searchable默认true),搜索在底层由 SearchView 提供,它通过getPathTowardsItem回溯父节点路径,从而把命中的叶子节点连同完整路径一起展示出来。
外观(Appearance)与尺寸(Size)
外观:default 与 subtle
appearance控制触发器的视觉样式,取值为'default' | 'subtle',默认'default'。示例(appearance.md):
const App = () => ( <> <Cascader data={data} appearance="default" placeholder="Default" w={224} /> <hr /> <Cascader data={data} appearance="subtle" placeholder="Subtle" w={224} /> </> );subtle外观弱化了边框与背景,适合嵌入工具栏、导航等需要低视觉噪音的场景。
尺寸:lg / md / sm / xs
size默认'md',支持四种规格(size.md):
<VStack> <Cascader size="lg" placeholder="Large" data={data} w={224} /> <Cascader size="md" placeholder="Medium" data={data} w={224} /> <Cascader size="sm" placeholder="Small" data={data} w={224} /> <Cascader size="xs" placeholder="Xsmall" data={data} w={224} /> </VStack>撑满容器(Block)
block为布尔属性,设置后触发器将占据父容器的整行宽度(block.md):
<Cascader block data={data} />在表单布局、移动端适配等场景中,block能让选择器与输入框视觉对齐。
弹出位置与防止溢出(Placement & Prevent Overflow)
弹出层的位置由placement控制,可选类型为:
type Placement = 'bottomStart' | 'topStart' | 'autoVerticalStart';默认值为'bottomStart'。preventOverflow用于防止浮动元素溢出容器,container可指定渲染容器。官方示例(placement.md)通过PlacementContainer在多个位置间切换演示,其中关键连线是:开启preventOverflow时把container传给组件,让弹出层被约束在指定容器内:
<Cascader w={224} preventOverflow={preventOverflow} data={data} placement={placement} container={preventOverflow ? container : undefined} placeholder={`Will pop from ${placement}`} />从源码看,placement与preventOverflow经由PickerToggleTrigger透传给内部定位逻辑(见 src/Cascader/Cascader.tsx 中PickerToggleTrigger的triggerPropKeys装配),这一点与 SelectPicker、TreePicker 等所有 picker 类组件一致。
父节点可选(Parent Selectable)
默认情况下 Cascader 只允许选择叶子节点。设置parentSelectable后,中间层级的父节点也可以被选中(parent-selectable.md):
<Cascader data={data} parentSelectable w={224} />该属性在CascaderProps中单独声明(见 src/Cascader/Cascader.tsx),选择行为由CascadeTree/hooks中的useSelect统一驱动。
自定义选项渲染(Custom Render)
Cascader 提供了四个渲染扩展点:renderTreeNode(自定义树节点)、renderColumn(自定义整列,可拿到{ items, parentItem, layer })、renderValue(自定义选中值显示)、renderSearchItem(自定义搜索结果)。官方示例(custom.md)给每一列加上表头、节点前加图标,并让触发器显示完整路径:
const headers = ['Job Area', 'Job Type', 'Name']; const Column = ({ header, children }) => ( <div> <div style={{ background: '#154c94', padding: '4px 10px', color: '#fff', textAlign: 'center' }}> {header} </div> {children} </div> ); const App = () => ( <Cascader data={data} w={224} columnWidth={160} renderTreeNode={(label, node) => ( <> <AdminIcon /> {label} </> )} renderColumn={(childNodes, { layer }) => { return <Column header={headers[layer]}> {childNodes}</Column>; }} renderValue={(value, activePaths, activeItemLabel) => { return activePaths.map(item => item.label).join(' > '); }} /> );实现层面,renderColumn与renderTreeNode都是 TreeView 的 props(见TreeViewProps定义),renderValue则由 Cascader 在usePaths提供的selectedPaths基础上调用——这正是「选中值显示为完整路径」能力的来源。
禁用与只读(Disabled & Read Only)
示例(disabled.md)覆盖了四种状态:
disabled:整个组件禁用;disabledItemValues:按值禁用指定选项(可传入多个值组成的数组,如['2', '1-1']);readOnly:只读,不可修改但保持交互外观;plaintext:纯文本展示(表单提交场景常用)。
<Field label="Disabled" disabled defaultValue="1-1" data={data} /> <Field label="Disabled option" data={data} defaultValue="1-1" disabledItemValues={['2', '1-1']} /> <Field label="ReadOnly" readOnly defaultValue="1-1" data={data} /> <Field label="Plaintext" plaintext defaultValue="1-1" data={data} />readOnly、plaintext等表单语义能力继承自FormControlPickerProps(见 src/Cascader/Cascader.tsx),与 rsuite 的 Form 表单体系(FormControl)无缝衔接;disabledItemValues在 TreeView 中被用于过滤可点击节点。
异步加载子级(Async Data)
文档明确说明异步加载机制:通过getChildren属性,且树节点上children字段长度为0时,触发按需加载子级。官方示例(async.md):
const [getNodes, fetchNodes] = mockAsyncData(); const initialData = getNodes(5); const App = () => { const [value, setValue] = React.useState(); return ( <Cascader value={value} onChange={setValue} placeholder="Select" w={224} data={initialData} columnWidth={200} getChildren={node => { return fetchNodes(node.id); }} renderTreeNode={(label, item) => ( <> {item.children ? <FolderFillIcon /> : <PageIcon />} {label} </> )} /> ); };这里的renderTreeNode利用item.children是否存在来区分「文件夹/页面」图标,配合getChildren形成典型的懒加载目录树体验。
源码佐证:
getChildren的签名是(item: Option) => Promise<Option[]>(见文档 Props 表);- Option 类型 中定义了
loading?: boolean字段,注释明确指出它「用于有级联关系并支持子级懒加载的组件,如 Cascader、MultiCascader」——加载中的节点会显示 Spinner 指示器; - TreeView 接收
loadingItemsSet,用于标记哪些节点处于加载状态,其加载图标使用SpinnerIcon渲染。
受控组件(Controlled)
Cascader 同时支持受控与非受控模式。value+onChange构成受控用法,defaultValue用于非受控初值。官方示例(controlled.md):
const App = () => { const [value, setValue] = React.useState('1-2-2'); return <Cascader value={value} onChange={setValue} data={data} w={224} />; };onChange签名为(value: string, event) => void,仅返回选中值本身;若需要完整路径,可结合onSelect((item, selectedPaths, event) => void)或renderValue获取selectedPaths。从源码看,受控状态通过useControlledhook 管理(见 src/Cascader/Cascader.tsx 的 hooks 装配),选中路径则由CascadeTree/hooks的usePaths基于parentMap回溯计算。
响应式:超小屏幕自动变为全宽 Drawer
文档明确:在超小屏幕上(extra-small screens),弹出层默认显示为全宽 Drawer;当选择器已经位于 Modal 或 Drawer 内部时,应设置responsive={false}保持定位浮层,避免嵌套遮罩冲突。
<Cascader data={data} block />responsive默认值为true。演示页位于 docs/pages/components/cascader/examples/responsive.tsx,页面组装见 examples/index.tsx。这一行为是 rsuite 移动端适配的组成部分:窄屏下全宽 Drawer 比小尺寸定位浮层更易点选,而responsive={false}则保证了 Modal/Drawer 内的「弹出层套弹出层」体验。
可访问性(Accessibility)
Cascader 内置了完整的 ARIA 与键盘交互支持,文档将其作为一等公民列出:
ARIA 属性
role="combobox":声明组合框角色;aria-haspopup="tree":指示 combobox 有一个弹出的树形列表框;aria-expanded:指示树形列表框是否展开;aria-controls:指示树形列表框元素的 ID;aria-activedescendant:指示当前焦点选项的 ID;- 当设置了
label时,aria-labelledby会被同时添加到 combobox 元素与 tree 元素上,值为label的id属性值。
键盘交互
| 按键 | 行为 |
|---|---|
| ↓ | 焦点移动到下一个树节点 |
| ↑ | 焦点移动到上一个树节点 |
| → | 展开当前(折叠状态的)树节点 |
| ← | 收起当前(展开状态的)树节点 |
| Enter | 选中焦点所在的树节点 |
| Esc | 关闭树形列表框 |
实现上,这些能力来自@/internals/Picker的useCombobox上下文与useToggleKeyDownEvent键盘事件绑定(见 src/Cascader/Cascader.tsx 的 import 与 TreeView 中的useCombobox()调用),焦点节点通过useFocusItemValue跟踪并映射为aria-activedescendant。
Props 完整说明(<Cascader>)
下表完整继承自官方文档(en-US:index.md;zh-CN:index.md):
| 属性 | 类型(默认值) | 说明 |
|---|---|---|
| appearance | 'default' \| 'subtle'('default') | 设置外观 |
| block | boolean | 占满父容器整行 |
| caretAs | ElementType | 自定义右侧箭头图标的组件 |
| childrenKey | string('children') | 设置选项子节点在data中的key |
| classPrefix | string('picker') | 组件 CSS 类的前缀 |
| cleanable | boolean(true) | 选中值是否可清除 |
| columnHeight | number | 设置选项列的高度 |
| columnWidth | number | 设置选项列的宽度(TreeView 默认140) |
| container | HTMLElement \| (() => HTMLElement) | 设置渲染的容器 |
| data * | [Option][] | 组件数据(必填) |
| defaultValue | string | 默认选中值(非受控) |
| disabled | boolean | 禁用整个组件 |
| disabledItemValues | string[] | 禁用指定值的选项 |
| getChildren | (item: Option) => Promise<Option[]> | 异步加载树节点的子级 |
| height | number(320) | 设置 Dropdown 的高度 |
| labelKey | string('label') | 设置选项显示内容在data中的key |
| loading | boolean(false) | 是否显示加载中状态指示器 |
| locale | PickerLocaleType | 本地化文案设置 |
| onChange | (value: string, event) => void | value改变时的回调 |
| onClean | (event) => void | 清除值后的回调 |
| onClose / onOpen | () => void | 关闭 / 打开回调 |
| onEnter / onEntering / onEntered | () => void | 弹出层过渡动画:进入前 / 进入中 / 进入后 |
| onExit / onExiting / onExited | () => void | 弹出层过渡动画:退出前 / 退出中 / 退出后 |
| onSearch | (search: string, event) => void | 搜索回调 |
| onSelect | (item: Option, selectedPaths: Option[], event) => void | 选项被点击选择后的回调 |
| open | boolean | 是否打开(受控弹出) |
| parentSelectable | boolean | 设置父节点为可选 |
| placeholder | ReactNode('Select') | 占位符 |
| placement | Placement('bottomStart') | 弹出位置 |
| popupClassName | string | 弹出层自定义 CSS 类名 |
| popupStyle | CSSProperties | 弹出层自定义样式 |
| preventOverflow | boolean | 防止浮动元素溢出 |
| renderColumn | (childNodes, column: { items, parentItem, layer }) => ReactNode | 自定义渲染选项列 |
| renderExtraFooter | () => ReactNode | 自定义弹出层页脚 |
| renderSearchItem | (node, items: Option[]) => ReactNode | 自定义搜索结果项 |
| renderTreeNode | (node, item: Option) => ReactNode | 自定义树节点 |
| renderValue | (value, selectedPaths: Option[], selected: ReactNode) => ReactNode | 自定义选中值显示 |
| responsive | boolean(true) | 超小屏幕是否以全宽 Drawer 显示弹出层 |
| searchable | boolean(true) | 是否可搜索 |
| size | 'lg' \| 'md' \| 'sm' \| 'xs'('md') | 组件尺寸 |
| toggleAs | ElementType('a') | 自定义触发元素类型 |
| value | string | 当前值(受控) |
| valueKey | string('value') | 设置选项值在data中的key |
配套的两种共享类型定义如下。
Option数据结构
interface Option<V> { /** 选项的值,对应数据中的 `valueKey`。 */ value: V; /** 选项显示内容,对应数据中的 `labelKey`。 */ label: ReactNode; /** 子选项数据,对应数据中的 `childrenKey`,为树形组件(TreePicker、Cascader 等)所拥有。 */ children?: Option<V>[]; /** 分组功能组件(CheckPicker、InputPicker 等)的属性。 */ groupBy?: string; /** 当前节点的子级是否加载中,用于有级联关系且懒加载子级的组件(Cascader、MultiCascader)。 */ loading?: boolean; }完整定义见 docs/pages/_common/types/item-data-type.md。
Placement类型
type Placement = 'bottomStart' | 'topStart' | 'autoVerticalStart';完整定义见 docs/pages/_common/types/placement-start.md。
源码结构:Cascader 的实现骨架
如果要在项目里深度定制 Cascader,可以顺着以下源码路径继续探索:
- src/Cascader/Cascader.tsx:组件主文件。组合
PickerToggle、PickerPopup、PickerToggleTrigger与CascadeTree的TreeView/SearchView;状态管理使用useControlled、usePaths、useSelect、useSearch、useActive、useFocusItemValue等 hooks; - src/CascadeTree/TreeView.tsx:多列联动视图,负责按
cascadePaths逐列渲染,默认columnWidth = 140、columnHeight = 200; - src/CascadeTree/SearchView.tsx:搜索视图,通过
getPathTowardsItem+parentMap回溯命中项的完整路径,renderSearchItem在此生效; - src/Cascader/index.tsx:对外导出入口,同时导出
CascaderProps类型; - src/CascadeTree/hooks:
usePaths(路径计算)、useSelect(选择逻辑)、useSearch(搜索状态)等核心 hooks 所在地。
这套「Picker 触发器 + 级联树视图」的组合也是MultiCascader复用同一CascadeTree的原因,理解 Cascader 后即可举一反三掌握 rsuite 全部级联类组件的用法。
小结
Cascader 是 rsuite 中数据驱动、开箱即用的层级选择组件:data一份树形数据即可渲染联动多列,parentSelectable控制父级可选,getChildren实现按需懒加载,renderColumn/renderTreeNode/renderValue提供从列头到选中值全链路的自定义能力,responsive与内置 ARIA/键盘交互则覆盖了移动端与无障碍两大工程要求。无论你正在搭建行政区划选择器、组织架构树还是商品类目筛选,本文的示例与 Props 明细都可以直接作为落地参考。
- 前端
- UI组件
【免费下载链接】rsuite
🧱 A suite of React components .
相关推荐
rsuite Cascader 级联选择器异步数据加载:getChildren 懒加载实战指南
rsuite Cascader 级联选择器异步数据加载:getChildren 懒加载实战指南 本篇技术指南聚焦 rsuite 的 Cascader (级联选择
前端UI组件Element(Vue 2.0)Cascader 级联选择器完整实战指南:从基础用法到动态加载与源码级原理
Element(Vue 2.0)Cascader 级联选择器完整实战指南:从基础用法到动态加载与源码级原理 Cascader 级联选择器是 Element UI
前端UI组件设计系统Naive UI Cascader 级联选择器完全指南:从基础用法到源码级原理
Naive UI Cascader 级联选择器完全指南:从基础用法到源码级原理 Cascader(级联选择器)是 Naive UI 中用于展示与选择 树形结构数
前端UI组件
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考