TreeSelect
树形选择器,单面板可展开/收起的树,单选叶子或任意节点;支持 multiple 多选(checkbox + 父子联动 + 多 tag 回显 + 收敛策略)、可搜索过滤(本地/远程 + 命中高亮)、异步加载子节点、虚拟滚动大数据树、自定义字段映射与节点/tag/触发器渲染。
如何引入
import { TreeSelect } from '@chenzy-design/svelte';基础树形选择
在树形结构中选择节点,支持搜索过滤与清空
多选与折叠
multiple 开启 checkbox 多选与父子联动,maxTagCount 折叠超出标签
仅选叶子节点
leafOnly 让父节点只展开不选中,仅叶子可作为最终值
禁用状态
禁用单个节点(disabled 字段)或整体禁用选择器
前缀与清除
自定义 prefix 图标、large 尺寸、默认展开指定节点并可一键清除
内嵌标签与自定义触发器
insetLabel 触发器内嵌标签;triggerRender 完全替换默认选择框(与 Cascader 一致)
搜索框在触发器
searchPosition='trigger' 配 filterTreeNode,把搜索输入框内嵌到触发器内而非浮层顶部
严格禁用
multiple + disableStrictly:勾选父节点不影响 disabled 子节点,禁用态独立
自定义已选项
renderSelectedItem 具名 snippet 自定义已选 tag 渲染(图标 + 自定义样式)
命令式搜索
bind:this 拿实例,调用 ref.search(...) 命令式触发面板内搜索
虚拟化
virtualize 对象开启大数据树虚拟滚动
远程搜索
remote 开启后输入仅触发 onSearch,由外部更新 treeData
标签换行
triggerTagWrap 让 trigger 内多选标签自动换行
默认展开
defaultExpandAll 初始化展开;expandAll 动态展开
受控
value 完全受控,配合 onChange
选中关系
checkRelation=unRelated 时父子选中互不影响
异步加载
loadData 展开时动态加载子节点
API 参考
TreeSelect
Props
| 属性 | 说明 | 类型 | 默认值 |
|---|---|---|---|
value | — | TreeKey|TreeKey[]|null | undefined |
defaultValue | — | TreeKey|TreeKey[]|null | null |
treeData | 树数据源;字段名可经 fieldNames 自定义 | TreeNode[] | [] |
fieldNames | 自定义节点字段名映射,适配任意后端数据(如 { key:'id', label:'name', children:'sub' })。派生只读映射;onChange 回传的 key 即原始字段值 | { key?: string; label?: string; children?: string } | { key:'key', label:'label', children:'children' } |
open | — | boolean | undefined |
defaultOpen | — | boolean | false |
multiple | checkbox 多选 + 父子联动,多 tag 回显 | boolean | false |
checkStrictly | 多选时父子勾选互不影响(向后兼容,等价 checkRelation=unRelated) | boolean | false |
checkRelation | 多选父子是否级联联动;unRelated 互不影响。checkStrictly=true 强制 unRelated | 'related'|'unRelated' | 'related' |
showCheckedStrategy | 回填值/Tag 收敛策略:all 全部勾选节点;parent 折叠为父;child 仅叶子。仅 related 生效 | 'all'|'parent'|'child' | 'all' |
maxTagCount | 多选回填 Tag 最大展示数,超出折叠为 +N(仅影响显示) | number | undefined |
placeholder | — | string | '请选择' |
size | — | 'small'|'default'|'large' | default |
status | — | 'default'|'warning'|'error' | default |
disabled | — | boolean | false |
showClear | 值不为空时 trigger 展示清除按钮(对齐 Semi) | boolean | false |
leafOnly | — | boolean | false |
defaultExpandAll | — | boolean | false |
defaultExpandedKeys | 默认展开的节点 key(非受控初始展开集,与 defaultExpandAll 取并集;对齐 Semi) | TreeKey[] | [] |
filterable | 面板搜索框过滤节点 + 高亮命中 | boolean | false |
filterTreeNode | 按输入筛选节点(对齐 Semi):true 开启搜索并默认按 treeNodeFilterProp 包含匹配;函数则自定义匹配谓词。与 filterable 其一为真即显示搜索框 | boolean | ((inputValue: string, treeNodeString: string, data?: TreeNode) => boolean) | undefined |
remote | 远程搜索:输入防抖后仅触发 onSearch,不本地过滤(外部更新 treeData) | boolean | false |
searchDebounce | onSearch 防抖毫秒(remote 时生效) | number | 300 |
onSearch | 远程搜索输入回调(防抖后) | (query: string) => void | undefined |
showIcon | 是否预留节点图标位(icon 提供时渲染在 label 前),与 Tree 对齐 | boolean | true |
loadData | 异步加载子节点:展开未加载的非叶子节点时调用,返回该节点子节点数组(加载中显示 spinner,竞态去重,不写回 treeData)。与 Tree 的 loadData 对齐 | (node: TreeNode) => Promise<TreeNode[]> | undefined |
virtualize | 列表虚拟化(对齐 Semi):传入对象即开启,仅渲染视口内可见行;height 视口高(默认 224)、itemSize 行高(默认 32)。复用 Tree 范式(core fixedRange),保持 role=tree/treeitem 语义 | { height?: number; width?: number | string; itemSize?: number } | undefined |
icon | 自定义节点图标,showIcon 为真时渲染在 label 前;参数含节点与展开态,与 Tree 的 icon API 对齐 | Snippet<[{ node: TreeNode; expanded: boolean; level: number }]> | undefined |
triggerRender | 完全自定义触发器渲染(替换默认选择框);参数含当前 value/placeholder/isOpen/disabled,与 Cascader.triggerRender 对齐 | Snippet<[{ value: TreeKey|TreeKey[]|null|undefined; placeholder: string; isOpen: boolean; disabled: boolean }]> | undefined |
insetLabel | 触发器内嵌标签,渲染在回填值/占位符之前(对齐 Semi insetLabel),消费 --cd-color/font-tree-select-label token | Snippet | string | undefined |
insetLabelId | 内嵌标签的 id(a11y 关联用),对齐 Semi insetLabelId | string | undefined |
motion | 下拉浮层开合动画(淡入);与 Cascader/Dropdown 的 motion 对齐。reduced-motion 退化 | boolean | true |
onChange | 多选返回 checked 全集数组,单选返回单 key | (value: TreeKey|TreeKey[]|null) => void | undefined |
onOpenChange | — | (open: boolean) => void | undefined |
ariaLabel | — | string | undefined |
virtualizeThreshold | 可见扁平行数 ≥ 此值时自动开启虚拟化;传入 virtualize 对象强制开启(超集,Semi 无) | number | 100 |
position | 浮层弹出位置(对齐 Semi,参考 Tooltip position);映射到 use:floating placement | string | 'bottomLeft' |
dropdownMatchSelectWidth | 浮层宽度对齐触发器(min-inline-size = 触发器宽) | boolean | true |
getPopupContainer | 浮层挂载容器,缺省 ConfigProvider 全局值再回退 document.body | () => HTMLElement | null | undefined | undefined |
destroyOnClose | 关闭即从 DOM 卸载浮层(重开重建);默认首开后保留 DOM 仅隐藏 | boolean | false |
borderless | 无边框模式:trigger 边框透明 | boolean | false |
prefix | trigger 前缀 | Snippet | string | undefined |
suffix | trigger 后缀 | Snippet | string | undefined |
clearIcon | 自定义清除按钮图标 | Snippet | undefined |
expandIcon | 自定义展开图标;也可传无参 Snippet 统一渲染 | Snippet<[{ node: TreeNode; expanded: boolean; level: number }]> | undefined |
arrowIcon | 自定义右侧下拉箭头(expandIcon 的别名) | Snippet | undefined |
showLine | 显示节点连接线(垂直导引线) | boolean | false |
labelEllipsis | 节点 label 单行省略截断,可关闭以允许换行 | boolean | true |
style | 选择框样式 | string | undefined |
autoAdjustOverflow | 浮层遮挡时自动调整方向 | boolean | true |
validateStatus | status 的别名(优先于 status) | 'default'|'error'|'warning' | undefined |
onBlur | 失焦回调 | (e: FocusEvent) => void | undefined |
onFocus | 聚焦回调 | (e: FocusEvent) => void | undefined |
preventScroll | 聚焦时阻止滚动 | boolean | false |
outerTopSlot | 面板顶部外层 slot(在搜索框之上) | Snippet | undefined |
outerBottomSlot | 面板底部外层 slot(在树之下) | Snippet | undefined |
searchAutoFocus | 面板打开时搜索框自动获焦 | boolean | false |
searchPosition | 搜索框位置:'dropdown' 面板内;'trigger' trigger 内 | 'dropdown'|'trigger' | 'dropdown' |
searchPlaceholder | 搜索框占位文字 | string | undefined |
treeNodeFilterProp | 搜索过滤属性 | string | 'label' |
showSearchClear | 搜索框右侧显示清除按钮(有内容时) | boolean | true |
showFilteredOnly | 搜索激活时仅显示命中节点,不显示祖先链 | boolean | false |
emptyContent | 无匹配/无数据占位内容(对齐 Semi emptyContent);未传回退 i18n TreeSelect.emptyText | string | Snippet | undefined |
searchRender | 自定义搜索框渲染:false 隐藏内置搜索框;Snippet 完全接管渲染(回调回填输入) | boolean | Snippet<[{ value: string; onInput: (v: string) => void; onKeydown: (e: KeyboardEvent) => void; placeholder: string }]> | undefined |
expandedKeys | 受控展开的节点 keys | TreeKey[] | undefined |
expandAll | 动态全部展开(受控/动态,区别于 defaultExpandAll) | boolean | false |
expandAction | 行点击展开方式:false 仅展开按钮;'click' 单击行;'doubleClick' 双击行 | false | 'click' | 'doubleClick' | false |
autoExpandParent | 展开节点时自动展开其所有祖先链 | boolean | false |
motionExpand | 展开/折叠动画 | boolean | true |
onExpand | 节点展开回调 | (expandedKeys: TreeKey[], info: { expanded: boolean; node: unknown }) => void | undefined |
autoMergeValue | 自动合并值:父节点全选时 value 不含后代(等价 showCheckedStrategy='parent') | boolean | true |
onChangeWithObject | onChange 回调携带完整节点对象而非仅 key | boolean | false |
showRestTagsPopover | 多选 maxTagCount 折叠出 +N 时,hover +N 用 Popover 浮层展示折叠掉的剩余全部 Tag | boolean | false |
restTagsPopoverProps | 透传给剩余 Tag Popover 浮层的额外 props(在默认 trigger=hover/position=top 之后展开,可覆盖) | Record<string, unknown> | undefined |
triggerTagWrap | trigger 多选 tags 换行显示(默认单行截断折叠) | boolean | false |
renderLabel | 自定义节点 label 渲染(仅替换文字部分) | Snippet<[{ label: string; data: TreeNode; searchWord: string }]> | undefined |
renderFullLabel | 完全自定义节点行渲染(替换整行内容) | Snippet<[{ node: TreeNode; expanded: boolean; level: number; checked: boolean; halfChecked: boolean; selected: boolean }]> | undefined |
renderSelectedItem | 自定义 trigger 已选 tag 渲染(多选时每个 tag 独立渲染) | Snippet<[{ node: TreeNode; onRemove: () => void }]> | undefined |
treeNodeLabelProp | 节点数据中用作显示 label 的字段名 | string | 'label' |
keyMaps | 自定义 key/label/value 字段映射(优先级高于 fieldNames 的 key/label 部分) | { key?: string; label?: string; value?: string } | undefined |
optionListStyle | 选项列表容器的内联 style | string | Record<string, string> | undefined |
loadedKeys | 受控已加载的节点 keys | Set<TreeKey> | undefined |
clickToHide | 单选选中后自动关闭面板 | boolean | true |
clickTriggerToHide | 面板开启时点击 trigger 关闭面板 | boolean | true |
disableStrictly | 严格禁用:disabled 节点不因父节点联动而影响,禁用态独立 | boolean | false |
dropdownMargin | 浮层与 trigger 的额外间距(px);数字映射到浮层 offset,对象取 marginTop | number | { marginTop?: number; marginBottom?: number; marginLeft?: number; marginRight?: number } | undefined |
dropdownClassName | 追加到浮层根节点的自定义类名(与内置类名并存) | string | undefined |
dropdownStyle | 合并进浮层根节点的内联样式(不覆盖内置定位样式) | string | Record<string, string> | undefined |
zIndex | 浮层层级(z-index),未传由 CSS 控制 | number | undefined |
onClear | 点击清除按钮回调 | (e: MouseEvent) => void | undefined |
onSelect | 节点选中回调 | (selectedKey: TreeKey, selected: boolean, node: unknown) => void | undefined |
onLoad | 异步加载完成回调(含已加载 key 集合与当前节点) | (loadedKeys: TreeKey[], treeNode: TreeNode) => void | undefined |
onVisibleChange | 面板可见性变化回调(与 onOpenChange 语义相同,Semi 风格别名) | (isVisible: boolean) => void | undefined |
Methods
| 属性 | 类型 | 说明 |
|---|---|---|
search(sugInput) | — | 命令式搜索:把值置给内部搜索态并触发过滤(对齐 Semi,用于外部自定义搜索框) |
Accessibility
| ARIA role | combobox |
- combobox 触发器 + role="tree" 面板 + role="treeitem"
- 有 children 节点 aria-expanded 标记展开态
- aria-selected 标记选中节点
- leafOnly 时非叶子节点仅切换展开,不可选
设计变量
| 变量 | 默认值 | 用法 |
|---|---|---|
--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) |