- 前端
- UI组件
【免费下载链接】rsuite
🧱 A suite of React components .
导读:本文围绕 rsuite 官方文档 Tree 组件禁用树节点示例 展开,系统讲解
disabledItemValues的使用方法、匹配规则与底层实现原理,并结合仓库源码(src/Tree)与测试用例给出可复制的实战方案。读完你既能快速上手禁用任意层级节点,也能理解禁用节点在点击、键盘导航、虚拟滚动与级联场景下的完整行为边界。
一、从官方示例看 disabledItemValues 的用法
rsuite<Tree>组件的disabledItemValues属性用于接收一个节点值数组,数组中列出的节点将被禁用(置灰、不可选中)。官方示例位于 docs/pages/components/tree/fragments/disabled.md:
import { Tree } from 'rsuite'; const data = [ { label: 'Node 1', value: '1', children: [ { label: 'Node 1-1', value: '1-1' }, { label: 'Node 1-2', value: '1-2' } ] }, { label: 'Node 2', value: '2', children: [ { label: 'Node 2-1', value: '2-1', children: [ { label: 'Node 2-1-1', value: '2-1-1' }, { label: 'Node 2-1-2', value: '2-1-2' } ] }, { label: 'Node 2-2', value: '2-2' } ] } ]; const App = () => ( <Tree data={data} disabledItemValues={['1', '2', '2-1-1', '2-1-2']} defaultExpandAll /> ); ReactDOM.render(<App />, document.getElementById('root'));观察这个示例,可以得到几个关键结论:
- 示例数据是一个两层半嵌套的树结构,
disabledItemValues中同时包含了父节点('1'、'2')和叶子节点('2-1-1'、'2-1-2'),说明禁用不受节点层级限制,根、父、叶子节点均可禁用; defaultExpandAll用于默认展开全部节点,让禁用效果在首屏即可完整呈现;- 组件属性表(见 zh-CN 文档 Props 表)对该属性的定义为:
disabledItemValues: string[],描述为“设置禁用树节点的值”。
二、匹配机制:按 valueKey 精确匹配
disabledItemValues匹配的是节点在valueKey上对应的值,而不是label或其他字段。valueKey默认为'value',可通过valueKey属性自定义(参考 src/Tree/Tree.tsx 中labelKey = 'label'、valueKey = 'value'的默认值)。
在底层实现中,禁用判断使用shallowEqual进行值比较。见 useTreeNodeProps.tsx:
const disabled = disabledItemValues.some(disabledItem => equal(disabledItem, nodeValue));其中equal即shallowEqual。这意味着匹配基于原语值的浅比较,字符串、数字类型的 value 均可匹配。测试用例也验证了这一行为,Tree.falsy.spec.tsx 覆盖了disabledItemValues={[0]}、disabledItemValues={['']}这类假值场景,说明0、空字符串等值同样可以正确命中并禁用对应节点。
需要特别提醒的是:树结构中每个节点的value必须唯一。useFlattenTree.ts 在扁平化数据时会对重复值打印警告:The value '${value}' is duplicated. Each node in the tree data must have a unique value.如果存在重复 value,disabledItemValues可能同时禁用多个节点,导致意外行为。
三、禁用后的行为边界
3.1 点击选择:直接失效
禁用节点的第一个行为是不可选中。TreeNode.tsx 的handleSelect在开头即拦截:
const handleSelect = useEventCallback((event: React.SyntheticEvent) => { if (disabled) { return; } onSelect?.(nodeData, event); });对应测试 Tree.spec.tsx 明确断言了“禁用节点不触发onSelect回调”:
it('Should not call `onSelect` callback when the item is disabled', () => { const onSelect = vi.fn(); render(<Tree data={data} onSelect={onSelect} disabledItemValues={['Master']} />); fireEvent.click(screen.getByRole('treeitem', { name: 'Master' })); expect(onSelect).not.toHaveBeenCalled(); });由于选择动作被拦截在TreeNode层,禁用节点既不会更新组件选中值,也不会触发onSelect/onChange,value状态完全不受影响。
3.2 键盘导航:自动跳过禁用节点
在键盘交互中,禁用节点不会被聚焦。focusableTree.ts 中的getFocusableItems在收集可聚焦节点时直接过滤掉禁用项:
const disabled = disabledItemValues.some(disabledItem => shallowEqual(disabledItem, node[valueKey]) ); if (!disabled && node.visible) { items.push(node); }因此使用↓/↑/Home/End遍历时,焦点会“跳过”禁用节点;按Enter选择焦点节点时,禁用节点因不在可聚焦集合中而无法被选中。这与 zh-CN 文档“键盘交互”小节 描述的键盘操作规则相互印证。
3.3 虚拟滚动:不渲染、不占焦点位
当开启virtualized虚拟滚动时,禁用节点同样从可聚焦集合中排除。useVirtualTreeFocus.ts 中通过disabledItemValues.includes(node[valueKey])判断并跳过。对应测试 Tree.virtual-focus.spec.tsx 验证了“虚拟列表在跳过禁用与折叠节点后,使用实际可见行索引定位焦点”,保证长列表下禁用节点的行为与普通模式一致。
3.4 展开 / 拖拽:仍可操作
禁用主要约束“选中”行为,并不阻止节点的展开/折叠与拖拽:
TreeNodeToggle的展开点击走的是handleExpand(TreeNode.tsx),其中没有对disabled做拦截,因此禁用父节点仍然可以展开查看其子节点;- 拖拽事件(
onDragStart/onDragEnter/onDragOver/onDrop等)同样没有禁用判断(TreeNode.tsx)。
从源码结构可以推断,若需要“连展开/拖拽一起禁掉”,disabledItemValues无法直接实现,需要在业务层配合onExpand回调或树数据的业务判断来补充限制。
四、在级联场景中的特殊语义
disabledItemValues有一个容易被忽略的行为:在**多选(multiple)级联(cascade)**场景下,禁用节点及其禁用父节点下的子孙节点,不参与选中状态的自动联动。
useFlattenTree.ts 的updateTreeNodeCheckState中,会向上遍历祖先链判断“自身是否禁用”或“是否存在被禁用的父节点”:
// Check if this node or any of its parents is disabled const isNodeDisabled = disabledItemValues.some((disabledValue: any) => shallowEqual(node[valueKey], disabledValue) ); let hasDisabledParent = false; let currentNode = node; while (currentNode.parent && !hasDisabledParent) { // 逐级检查父节点是否在 disabledItemValues 中 ... } // Skip disabled nodes - they should not be affected by cascade or value changes if (isNodeDisabled || hasDisabledParent) { return; }这一实现的业务含义是:
- 禁用节点自身不会被级联勾选逻辑“强行选中”或“强行取消”;
- 被禁用节点的子孙节点(父节点被禁用)同样被跳过,避免出现“父级不可选、子级却被级联操作”的矛盾状态。
也就是说,在设计多选树时,disabledItemValues是一个比“仅隐藏禁用项”更强的控制手段:它把禁用节点及其子树从级联状态计算中整体隔离出去。
五、样式与无障碍:disabled 的呈现方式
禁用节点在视觉与无障碍层面都有专门处理。
5.1 视觉样式
样式定义在 src/Tree/styles/index.scss:
&-disabled { color: var(--rs-listbox-option-disabled-text); cursor: var(--rs-cursor-disabled); ... } &-disabled.rs-tree-node-active > .rs-tree-node-label { color: var(--rs-listbox-option-disabled-selected-text); }- 禁用节点使用
--rs-listbox-option-disabled-text颜色变量(置灰文本)与禁用光标(--rs-cursor-disabled); - 禁用状态的激活节点(
rs-tree-node-active)有独立的“禁用-选中”配色,防止样式冲突; - 类名由 TreeNode.tsx 拼接:
withPrefix({ disabled, active, 'text-muted': disabled, focus }),即同时挂载rs-tree-node-disabled与rs-tree-node-text-muted。
5.2 ARIA 无障碍
TreeNode.tsx 为禁用节点输出aria-disabled={disabled}。这与 zh-CN 文档“可访问性”小节 的说明一致:“有aria-disabled属性来指示树节点是否被禁用。”屏幕阅读器可据此向用户宣告节点的禁用状态,虚拟滚动场景下的aria-posinset/aria-setsize位置信息也会在禁用节点被跳过的前提下正确计算(见 Tree.virtual-position.spec.tsx 对aria-disabled的断言)。
六、实战建议与注意事项汇总
结合文档与源码,以下是使用disabledItemValues时的关键注意事项:
- 值必须与
valueKey对齐:默认匹配节点的value字段,自定义valueKey后需同步调整数组内容; - 值必须唯一:重复 value 会触发控制台警告,并可能导致意外禁用多个节点(useFlattenTree.ts);
- 支持假值:
0、空字符串等假值可以被正常禁用(Tree.falsy.spec.tsx); - 仅约束选择:禁用节点不可点击选中、不可被键盘聚焦,但仍可展开/折叠、可拖拽;如需禁止这些操作需业务层配合;
- 级联隔离:多选级联场景下,禁用节点及其子树不参与勾选状态联动(useFlattenTree.ts);
- 无障碍同步:禁用状态会通过
aria-disabled暴露给辅助技术,虚拟滚动下位置信息同样跳过禁用项。
七、关联阅读
- 官方完整示例文档:docs/pages/components/tree/fragments/disabled.md(本文示例出处)
- Tree 组件完整 Props 表:zh-CN、en-US
- 组件入口与属性分发:src/Tree/Tree.tsx
- 节点渲染与点击拦截:src/Tree/TreeNode.tsx
- 禁用判断与级联逻辑:src/Tree/hooks/useFlattenTree.ts、src/Tree/hooks/useTreeNodeProps.tsx
- 键盘焦点过滤:src/Tree/utils/focusableTree.ts
- 禁用样式:src/Tree/styles/index.scss
- 相关测试:Tree.spec.tsx、Tree.falsy.spec.tsx、Tree.virtual-focus.spec.tsx
- 前端
- UI组件
【免费下载链接】rsuite
🧱 A suite of React components .
相关推荐
rsuite CheckTree 节点禁用完全指南:disabledItemValues 用法、级联联动与无障碍实现
rsuite CheckTree 节点禁用完全指南:disabledItemValues 用法、级联联动与无障碍实现 <CheckTree 是 rsuite 提
前端UI组件RSuite Tree 组件虚拟化实战:用 virtualized 与 scrollToItem 渲染千级节点树
RSuite Tree 组件虚拟化实战:用 virtualized 与 scrollToItem 渲染千级节点树 RSuite 的 <Tree 组件用于展示树形
前端UI组件rsuite MultiCascader 禁用与只读状态完整指南:disabled / disabledItemValues / readOnly / plaintext 实战解析
rsuite MultiCascader 禁用与只读状态完整指南:disabled / disabledItemValues / readOnly / plai
前端UI组件
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考