antd Cascader 多选模式(multiple)实战:disableCheckbox 禁用勾选与禁用态样式定制
导读
Cascader 是 Ant Design 中用于层级选择的核心组件,默认只允许单选一个末级节点;本篇文章聚焦其「多选(multiple)」使用场景。你将学会如何在 options 数据上通过 disableCheckbox 字段单独禁用某一个节点的 checkbox、如何理解父级全选时对禁用节点的处理逻辑,以及如何借助 CSS 类名定制禁用态的视觉样式。文章以仓库中的 multiple.md 官方演示为主体,并结合 源码实现 与 测试用例 深入剖析其底层机制。
一次选择多个选项:多选模式的基础用法
Cascader 的多选能力由 multiple 属性开启。仓库中的官方演示 multiple.tsx 给出了最小可运行示例,其核心代码如下:
import React from 'react';
import type { CascaderProps } from 'antd';
import { Cascader } from 'antd';
const onChange: CascaderProps<Option, 'value', true>['onChange'] = (value) => {
console.log(value);
};
const App: React.FC = () => (
<Cascader
style={{ width: '100%' }}
options={options}
onChange={onChange}
multiple
maxTagCount="responsive"
/>
);
export default App;
关键点说明:
multiple:布尔属性,置为true后下拉面板中每个选项前会出现 checkbox,已选项以标签(Tag)形式回填到输入框中。从 CascaderProps 的类型定义可以看到multiple?: Multiple,且存在泛型Multiple extends boolean,TS 会据此推导出 onChange 回调中 value 的结构。maxTagCount="responsive":控制已选标签的最大展示数量,"responsive"表示当标签宽度超出容器时自动折叠为+N,适用于大量多选的场景,避免输入框被标签撑满。onChange的类型签名:多选时回调参数value是「二维数组」,每一项对应一条从根到叶的完整路径,例如[['bamboo', 'little', 'fish']]。上面用CascaderProps<Option, 'value', true>['onChange']精确标注了多选版本的回调类型。options:级联数据源,接口定义为{ value, label, children?, disableCheckbox? },其中children递归声明层级,disableCheckbox是本文的核心字段,见下一节。
提示:上述示例可直接在仓库 demo 页面中运行调试,类型导入
import { Cascader } from 'antd'与日常业务使用方式一致。
数据层:用 disableCheckbox 字段禁用单个 checkbox
多选场景下,「禁用」是分级别的——我们通常希望在整棵级联树可用的前提下,仅让某一个特定节点无法被勾选。此时不需要设置组件级 disabled(那会整体失效),而是在该节点的数据中声明 disableCheckbox: true。
在 multiple.tsx 的数据结构中,示例把 disableCheckbox 声明为 Option 接口的可选字段,并作用于第三层叶子节点:
interface Option {
value: string | number;
label: string;
children?: Option[];
disableCheckbox?: boolean;
}
// 摘录:位于 Bamboo → Little 路径下的叶子节点
{
label: 'Toy Fish',
value: 'fish',
disableCheckbox: true, // 该节点的 checkbox 被禁用,无法勾选
}
这段数据在「字段自定义」层面说明了 disableCheckbox 的取值对象:它是作用于单个 option 节点的数据字段,而非 Cascader 组件的顶层属性。它只影响多选模式下 checkbox 的勾选状态:
- 被标记的节点,其前方的 checkbox 呈现禁用态,用户无法通过点击它完成勾选;
- 其它同级、父级节点不受影响,可以正常勾选与取消。
与 disabled 字段的区别
同目录下的 disabled-option.md 演示了另一种禁用方式——通过在 options 中指定 disabled 字段来整体禁用某个选项(该节点不可点击、不可选中,通常还伴随灰显样式)。二者适用场景不同,可对照选用:
| 数据字段 | 生效前提 | 禁用粒度 |
|---|---|---|
disabled |
单选/多选均生效 | 整个选项(含路径点击)不可用 |
disableCheckbox |
多选(multiple)模式下生效 |
仅该节点的勾选框被禁用 |
源码机制:multiple 是如何变成 checkbox 的
在 Ant Design 的封装层,multiple 并不会直接透传给底层组件,而是被转换成了一个 checkable 渲染结果。查看 useCheckable.tsx,逻辑非常简洁:
import * as React from 'react';
export default function useCheckable(cascaderPrefixCls: string, multiple?: boolean) {
return React.useMemo(
() => (multiple ? <span className={`${cascaderPrefixCls}-checkbox-inner`} /> : false),
[cascaderPrefixCls, multiple],
);
}
由此可以推断整个调用链路:
- Cascader 主体组件 中调用
useCheckable(cascaderPrefixCls, multiple),把布尔型multiple翻译成带-checkbox-inner类名的 React 元素; - 该元素作为
checkable属性传入底层@rc-component/cascader(<RcCascader checkable={checkable} ... />); rc-cascader在checkable存在时即为每个节点渲染 checkbox,实现多选与父子联动勾选逻辑。
也就是说:Cascader 的「多选」在底层实现上就是「可勾选(checkable)」,而 disableCheckbox 正是 rc-cascader 在渲染 checkbox 时识别的禁用信号,最终表现为 checkbox 呈现禁用态且不参与勾选。
多选回填策略:SHOW_CHILD 与 SHOW_PARENT
多选模式下,父子节点同时被勾选后存在「回填哪些路径」的问题。仓库在 index.tsx 中直接从底层组件导出两个常量:
const { SHOW_CHILD, SHOW_PARENT } = RcCascader;
并挂载为 Cascader.SHOW_PARENT 与 Cascader.SHOW_CHILD(index.tsx),供业务方通过 showCheckedStrategy 指定回填粒度。可参考配套演示 showCheckedStrategy.tsx:
const { SHOW_CHILD } = Cascader;
<Cascader
options={options}
onChange={onChange}
multiple
maxTagCount="responsive"
showCheckedStrategy={SHOW_CHILD}
defaultValue={[
['bamboo', 'little', 'fish'],
['bamboo', 'little', 'cards'],
['bamboo', 'little', 'bird'],
]}
/>
SHOW_CHILD:只回填叶子节点(子项)路径;SHOW_PARENT:当某父级下所有子项都被勾选时,仅回填父级路径。
该属性与 disableCheckbox 都属于多选行为配置,在实战中常组合使用,用来控制最终提交给后端的 value 形态。
禁用态的样式定制:通过类名修改
官方演示 multiple.md 特别指出:disableCheckbox 节点的禁用样式可以通过类名进行修改。要精准定制,就需要知道实际渲染出的 DOM 类名。从 测试用例 可以确认关键类名:
expect(container.querySelectorAll('.ant-cascader-checkbox-disabled')).toHaveLength(1);
expect(container.querySelectorAll('.ant-cascader-checkbox')).toHaveLength(4);
expect(container.querySelectorAll('.ant-cascader-checkbox-checked')).toHaveLength(3);
即在多选下拉面板中:
- 每个节点前的勾选框渲染为
.ant-cascader-checkbox; - 处于禁用态的勾选框额外叠加
.ant-cascader-checkbox-disabled(即disableCheckbox生效时节点出现的禁用类); - 被勾选的节点呈现
.ant-cascader-checkbox-checked。
通过 CSS 覆盖禁用样式
获得类名后,可用 CSS 自行覆盖禁用态视觉效果,例如让禁用 checkbox 呈现自定义颜色而不只是默认灰显:
/* 修改禁用 checkbox 的外观:去掉默认全灰,改为描边 + 斜杠提示 */
.ant-cascader-checkbox-disabled .ant-cascader-checkbox-inner {
border-color: #ff7875;
background: #fff1f0;
}
.ant-cascader-checkbox-disabled.ant-cascader-checkbox-checked
.ant-cascader-checkbox-inner {
background-color: #ff7875;
}
注意:类名中的
cascader前缀对应默认prefixCls(即ant-),若通过 ConfigProvider 或组件prefixCls修改了前缀,请同步替换选择器前缀。
样式作用域如何限定
若担心全局覆写影响其它页面,推荐将覆盖样式绑定在组件级 className 上。示例中 Cascader 接收 style={{ width: '100%' }},同样地你可以传入 className/rootClassName 限定输入框根节点;而下拉面板的类名可通过 classNames.popup.root(v5 语义化 API)或兼容的 popupClassName 指定。将上述选择器写成 my-cascader .ant-cascader-checkbox-disabled ...,即可把样式限制在当前组件范围内。
行为验证:父级全选会「跳过」被禁用的子节点
disableCheckbox 一个容易误解的行为点是:当父节点 checkbox 被勾选(全选所有子节点)时,被禁用 checkbox 的子节点是否会被一并选中?仓库测试 index.test.tsx 明确给出了预期:
“Check all children except disableCheckbox When the parent checkbox is checked”——勾选父节点时,除
disableCheckbox节点外的所有子节点被选中。
测试构造了如下结构并断言点击父级 checkbox 后,被勾选项数量为 3(而非 4,因为 fj 节点声明了 disableCheckbox: true):
<Cascader
multiple
options={[
{
label: '台湾',
value: 'tw',
children: [
{ label: '福建', value: 'fj', disableCheckbox: true },
{ label: '兰州', value: 'lz' },
{ label: '北京', value: 'bj' },
],
},
]}
/>
同时断言面板中该节点确实带 .ant-cascader-checkbox-disabled 禁用类。因此我们可以将这一行为总结为产品层面的明确契约:
- 禁用节点永远不被自动勾选——即使父级执行「全选」,
disableCheckbox节点也会被自动跳过; - 禁用节点不阻断父级操作——父节点仍可正常勾选其允许选中的子项。
这一细节对“不完全级联选择”类业务(如目录权限、区域配额)至关重要,可直接作为验收用例写入团队测试。
写在最后:多选 Cascader 的组合使用建议
综合官方演示与仓库实现,落地一个多选 Cascader 时建议按以下顺序梳理需求:
- 开启多选:设置
multiple,必要时配合maxTagCount控制已选标签展示; - 定义数据模型:在 Option 类型中补充
disableCheckbox?: boolean,对个别禁勾节点置为true;若需整体禁用选项则改用disabled字段; - 处理回填策略:按后端需要的 value 形态设置
showCheckedStrategy={Cascader.SHOW_CHILD}或SHOW_PARENT; - 定制禁用样式:利用
.ant-cascader-checkbox-disabled类名(配合组件级className限定作用域)覆盖默认灰显效果; - 验证父子联动:参照 测试用例 的行为契约,确保禁用节点在父级全选时被正确跳过。
说明:Cascader 基于
rc-cascader实现多选与勾选联动,disableCheckbox属于数据层(option 字段)能力;相关实现可继续阅读 Cascader 封装入口 与 useCheckable 钩子 深入理解。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0624
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00