Tree
树形控件(严格对齐 Semi):层级展示节点,支持展开/收起、单选/多选(multiple 驱动 checkbox 父子联动含半选 mixed)、内置搜索高亮。值通道统一走 value/onChange。受控 value/expandedKeys 均不回写,仅通过 onChange/onExpand/onSelect/onSearch 通知。键盘导航遵循 WAI-ARIA APG Tree View(单一 tab stop + aria-activedescendant)。
如何引入
import { Tree } from '@chenzy-design/svelte';基础用法
默认单选,每级菜单项均可选择。
多选
multiple + checkable:子项全选自动勾选父项,部分选中显半选。
可搜索
filterTreeNode 开启搜索,命中高亮 + 自动展开祖先;showFilteredOnly 只展示命中结果。
自定义搜索框
searchRender 自定义搜索框渲染(复用 Input 组件)。
手动触发搜索
searchRender={false} 隐藏内置框,经组件实例 search() 由外部输入驱动。
简单 JSON 数据
treeDataSimpleJson 传入扁平键值对,自动转为树。
行显示节点
blockNode(默认 true)整行高亮;false 时仅高亮 label。
自定义节点内容
renderLabel snippet 自定义节点渲染(父节点加计数标签)。
自定义图标
icon snippet 按叶子/展开态渲染文件夹与文件图标。
目录树模式
directory:整行块 + 内置目录/文件图标 + 点击整行展开。
禁用
disableStrictly:禁用节点勾选态不受父/子联动改变。
节点选中关系
checkRelation 'related'(联动+半选)与 'unRelated'(互不影响)。
默认展开
defaultExpandAll 仅初始化生效;expandAll 数据更新后仍生效。
受控
expandedKeys / value 受控,外部按钮控制展开与选中。
自动展开父节点
autoExpandParent:仅指定叶子也会展开其祖先链。
自定义展开图标
expandIcon snippet 自定义展开/收起箭头(+/− 号)。
连接线
showLine 显示节点之间的层级连接线(├ / └ / 竖线)。
虚拟化
1050 节点仅渲染视口内行;scrollTo() 滚动到指定节点。
异步加载
loadData 展开时动态拉取子节点,叶子需标 isLeaf。
动态更新数据
切换数据集,expandAll 保持全展开。
可拖拽
draggable + onDrop 实现节点拖拽排序(before / inside / after)。
高级定制·叶子分组勾选
renderFullLabel 只在叶子渲染勾选框,父节点仅分组(leafOnly)。
高级定制·单选高亮子节点
renderFullLabel + onSelect:选中父节点同时高亮其子孙。
字段映射
keyMaps 把后端 id/name/sub 映射为标准字段。
自定义搜索谓词
filterTreeNode 传函数自定义命中逻辑(按 label 前缀),命中节点祖先链自动展开。
开启搜索的展开受控
受控 expandedKeys 时搜索不自动展开,用 onSearch 的 filteredKeys 回写展开集。
可拖拽的高级定制
draggable + renderFullLabel 同用:整行自定义 + 拖拽排序 + 选中高亮子孙。
API 参考
Tree
Props
| 属性 | 说明 | 类型 | 默认值 |
|---|---|---|---|
treeData | 树数据源;字段名可经 keyMaps 自定义 | TreeNodeData[] | [] |
treeDataSimpleJson | 简单 JSON 形式的树数据(对齐 Semi):扁平 { key: value } 键值对,key 同时作 key/label,value 作节点 value,嵌套对象转子树。treeData 非空时优先,忽略此项 | Record<string, unknown> | undefined |
keyMaps | 自定义节点字段名映射(对齐 Semi keyMaps),适配任意后端数据(如 { key:'id', label:'name', children:'sub' })。派生只读映射,回调回传原始节点 | { key?: string; label?: string; children?: string } | { key:'key', label:'label', children:'children' } |
value | 受控选中值(对齐 Semi value);单选为标量、multiple 时为选中 key 数组(含父子联动结果)。onChangeWithObject 时为节点对象形态。受控时不回写 | TreeKey | TreeNodeData | Array<TreeKey | TreeNodeData> | null | undefined |
defaultValue | 非受控初始选中值;形态同 value | TreeKey | TreeNodeData | Array<TreeKey | TreeNodeData> | null | null |
onChangeWithObject | 以对象形态收发选中项:开启后 onChange 的 value 及受控 value/defaultValue 均为节点对象(含 label/value/其它字段),对象标识优先取 key 缺省回退 value | boolean | false |
multiple | 多选模式(对齐 Semi multiple):开启渲染 checkbox + 父子联动,值经 value/onChange 收发 | boolean | false |
disableStrictly | 严格禁用:disabled 节点勾选态被锁定,不能通过父/子级联动改变(区别于普通 disabled 仅禁直接点击)。仅 multiple 联动下有意义 | boolean | false |
leafOnly | 多选时 onChange 回传的 value 只含叶子节点 key(滤掉父/半选节点) | boolean | false |
checkRelation | 多选父子勾选联动关系(对齐 Semi)。'related'(默认)联动含半选;'unRelated' 父子独立无半选 | 'related' | 'unRelated' | 'related' |
expandedKeys | 受控展开。受控时不回写 | TreeKey[] | undefined |
defaultExpandedKeys | 非受控初始展开 | TreeKey[] | [] |
defaultExpandAll | 初始展开全部 | boolean | false |
autoExpandParent | 自动展开父节点(对齐 Semi 默认 false):初次挂载时把初始展开节点的祖先链并入;开启后收起父节点需先收起其展开的子节点 | boolean | false |
expandAction | 展开触发方式:false 仅点箭头;'click' 点整行展开;'doubleClick' 双击整行展开(箭头任意模式可点) | false | 'click' | 'doubleClick' | false |
autoMergeValue | 多选 value 自动合并父子:父节点完全选中时 onChange 回传只保留父不含子孙。仅 multiple 联动且 leafOnly=false 时有意义 | boolean | true |
labelEllipsis | label 超长单行省略;未显式传时跟随虚拟化 | boolean | false(virtualize 时 true) |
preventScroll | 组件内 focus() 时是否阻止浏览器滚动文档(作用于导出的命令式 focus 方法) | boolean | false |
showLine | 显示层级连接线(├/└/竖线,对齐 Semi showLine) | boolean | false |
virtualize | 列表虚拟化(对齐 Semi virtualize):传对象即开启,itemSize(行高 px)必传;仅渲染视口内可见行,适合大数据树;开启强制关闭动画 | { itemSize: number; height?: number | string; width?: number | string } | undefined |
filterTreeNode | 是否根据输入项筛选(对齐 Semi):true 用内置谓词(按 treeNodeFilterProp 字段包含匹配),传函数自定义命中逻辑;命中节点祖先链自动展开 | boolean | ((input: string, node: TreeNodeData) => boolean) | false |
treeNodeFilterProp | 内置搜索匹配节点的哪个字段(仅内置谓词生效,传自定义谓词时由函数决定) | string | 'label' |
searchStyle | 搜索框内联样式(透传到 input style) | string | undefined |
searchClassName | 搜索框附加 class(追加到 input) | string | undefined |
showClear | 搜索框有内容时显示清除按钮,点击清空(对齐 Semi showClear) | boolean | true |
showFilteredOnly | 搜索状态下只渲染命中节点及其祖先链,隐藏其它未命中节点(默认 false 展示全树、命中高亮、祖先自动展开) | boolean | false |
blockNode | 整行点击选中(对齐 Semi 默认 true;directory 时强制整行) | boolean | true |
directory | 目录树模式:整行块 + 内置目录/文件图标 + 默认点击整行展开 | boolean | false |
motion | 展开/收起动画开关;virtualized 时强制关闭 | boolean | true |
expandAll | 展开全部:数据变化时仍生效(区别于仅初始化的 defaultExpandAll);仅非受控展开有意义 | boolean | false |
loadedKeys | 受控已加载节点 key,配合 loadData;已加载节点展开时不再触发 loadData | TreeKey[] | undefined |
style | 根容器内联样式(对齐 Semi style);设 height 时列表区限高滚动 | string | undefined |
class | 根元素自定义类名(对齐 Semi className) | string | undefined |
searchPlaceholder | 搜索框占位文案(不传用内置 i18n) | string | undefined |
searchRender | 自定义搜索框渲染;传 false 隐藏内置搜索框(仍可经 search() 方法驱动) | false | Snippet<[SearchRenderContext]> | undefined |
onSelect | 节点选中回调(早于 onChange) | (key, selected, node) => void | undefined |
onDragOver | 拖拽悬停在候选目标上 | (info) => void | undefined |
onDragLeave | 拖拽离开候选目标 | (info) => void | undefined |
onDragEnd | 拖拽结束(无论是否成功放下) | (info) => void | undefined |
renderFullLabel | 完全接管整行渲染(叶子分组勾选、单选高亮子节点等高级场景) | Snippet<[FullLabelContext]> | undefined |
disabled | 整树禁用 | boolean | false |
emptyContent | 空态文案 | string | undefined |
ariaLabel | 无障碍标签 | string | undefined |
loadData | 异步加载子节点:展开未加载的非叶子节点时调用 | (node) => Promise<TreeNodeData[]> | undefined |
onLoad | 异步加载完成回调 | (loadedKeys: string[], info: { event: 'load'; node: TreeNodeData }) => void | undefined |
draggable | 启用 HTML5 拖拽排序:节点可拖动改变层级/顺序(before/inside/after) | boolean | false |
autoExpandWhenDragEnter | 拖拽到节点内部(inside)时是否延时自动展开该节点。仅 draggable 时有意义 | boolean | true |
hideDraggingNode | 是否隐藏拖拽跟随的 dragImg(设透明 drag image)。仅 draggable 时有意义 | boolean | false |
renderDraggingNode | 自定义拖拽 dragImg 元素,优先级高于 hideDraggingNode。仅 draggable 时有意义 | (nodeInstance: HTMLElement, node: TreeNodeData) => HTMLElement | undefined |
onDoubleClick | 节点双击回调 | (e: MouseEvent, node: TreeNodeData) => void | undefined |
onDrop | 放下时回调;受控数据由父组件按 info 重排 treeData,组件不内部改 | (info: { dragNode, dropNode, dropPosition }) => void | undefined |
onDragStart | 开始拖拽节点 | (node: TreeNodeData) => void | undefined |
onDragEnter | 拖拽进入候选目标节点 | (info: { dragNode: TreeNodeData; dropNode: TreeNodeData }) => void | undefined |
onContextMenu | 节点右键菜单回调(对齐 Semi onContextMenu) | (e: MouseEvent, node: TreeNodeData) => void | undefined |
onSearch | 搜索关键词变化回调(对齐 Semi);第二参为因搜索而展开的祖先链 key | (value: string, filteredExpandedKeys: string[]) => void | undefined |
onChange | 选中变更(对齐 Semi):单选回 key,多选回选中 key 数组 | (value) => void | undefined |
onExpand | 展开/收起回调(对齐 Semi onExpand) | (expandedKeys, { expanded, node }) => void | undefined |
renderLabel | 自定义节点内容(对齐 Semi renderLabel) | Snippet | undefined |
icon | 自定义节点图标(对齐 Semi icon;传入时渲染在 label 前) | Snippet<[{ node, expanded, isLeaf }]> | undefined |
expandIcon | 自定义展开/收起图标(对齐 Semi expandIcon);参数含节点、展开态与加载态 | Snippet<[{ node: TreeNodeData; expanded: boolean; loading: boolean }]> | undefined |
suffix | 节点尾部操作区(渲染在 label 右侧) | Snippet<[{ node: TreeNodeData }]> | undefined |
dragGhost | 自定义拖拽幽灵节点 | Snippet<[{ node: TreeNodeData }]> | undefined |
Events
| 事件 | 载荷 | 说明 |
|---|---|---|
onChange | — | 选中变更:单选回选中 key(或节点对象),多选回选中 key 数组 |
onSelect | — | 单个节点选中:(key, selected, node),早于 onChange |
onExpand | — | 展开/收起:(expandedKeys, { expanded, node }) |
onDrop | — | 拖拽放下:{ dragNode, dropNode, dropPosition: before|inside|after } |
Slots
| 名称 | 说明 |
|---|---|
renderLabel | 自定义节点内容渲染:{ node, level, searchValue, selected, checked } |
renderFullLabel | 整行接管渲染:FullLabelContext(data/level/style/className/expandIcon/checkStatus/expandStatus/onClick/onCheck/onExpand…) |
searchRender | 自定义搜索框:SearchRenderContext(value/placeholder/onChange/onClear/showClear/disabled) |
icon | 自定义节点图标:{ node, expanded, isLeaf } |
expandIcon | 自定义展开图标:{ node, expanded, loading } |
suffix | 节点尾部操作区:{ node } |
Methods
| 属性 | 类型 | 说明 |
|---|---|---|
focus | — | 命令式聚焦树容器(尊重 preventScroll) |
search | — | 命令式触发搜索(对齐 Semi):(value: string) => void,配合 searchRender=false |
scrollTo | — | 虚拟化滚动到节点(对齐 Semi):({ key, align? }) => void |
Accessibility
- role=tree(aria-multiselectable=multiple)容器为单一 tab stop,焦点通过 aria-activedescendant 指向当前高亮 treeitem;每行 role=treeitem 含 aria-level/setsize/posinset/expanded/disabled,单选时 aria-selected、多选时 aria-checked 支持 true/false/"mixed"(半选)。方向键导航:↑↓ 移动、→ 展开/进入子、← 折叠/回父、Home/End 首末、Enter 选中、Space 勾选或选中。
设计变量
| 变量 | 默认值 | 用法 |
|---|---|---|
--cd-color-tree-option-bg-active | var(--cd-color-primary-light-default) | 树选项选中/激活背景($color-tree_option-bg-active) |
--cd-color-tree-option-bg-hover | var(--cd-color-fill-0) | 树选项悬停背景($color-tree_option-bg-hover) |
--cd-color-tree-option-disabled-text-default | var(--cd-color-disabled-text) | 禁用树选项文字颜色($color-tree_option_disabled-text-default) |
--cd-color-tree-option-draggable-insert-border-default | var(--cd-color-primary) | 可拖拽插入指示线颜色($color-tree_option_draggable_insert-border-default) |
--cd-color-tree-option-highlight-text | var(--cd-color-primary) | 搜索命中高亮文本色($color-tree_option_hightlight-text) |
--cd-color-tree-option-icon-active | var(--cd-color-black) | 展开图标按下色($color-tree_option-icon-active) |
--cd-color-tree-option-icon-default | var(--cd-color-text-2) | 展开箭头 / 节点图标颜色($color-tree_option-icon-default) |
--cd-color-tree-option-icon-hover | var(--cd-color-text-0) | 展开图标悬停色($color-tree_option-icon-hover) |
--cd-color-tree-option-line | var(--cd-color-text-3) | showLine 连接线颜色(Semi 用 --semi-color-text-3) |
--cd-color-tree-option-loading-icon-default | var(--cd-color-primary) | 树选项加载 spin 颜色($color-tree_option_loading-icon-default) |