VirtTree API
原生版的树没有"属性 / 插槽 / 事件"三件套,只有构造函数的三个参数:
import { VirtTree } from '@virt-list/vanilla';
import '@virt-list/vanilla/src/tree/tree.css';
const tree = new VirtTree(container, options, events);options:下方配置项与渲染函数,对应框架版的属性与插槽;events:下方事件回调,键名一律 camelCase(框架版模板里的@drag-start在这里是dragstart);- 选中 / 展开 / 勾选没有
.sync双向绑定,初值走options,之后用暴露方法 读写,变化由events通知。
配置项
| 参数 | 说明 | 类型 | 默认值 | 是否必须 |
|---|---|---|---|---|
| list | 树形数据 | TreeNodeData[] | - | |
| fieldNames | 字段名映射,见下方 TreeFieldNames | TreeFieldNames | - | - |
| estimatedSize | 预估尺寸 | number | 32 | - |
| fixedSize | 是否为固定高度,可以提升性能 | boolean | false | - |
| buffer | 上下两侧的渲染缓冲节点数 | number | 0 | - |
| indent | 相邻级节点间的水平缩进,单位为像素 | number | 16 | - |
| iconSize | 图标大小 | number | 16 | - |
| itemGap | 元素之间的间距 (元素尺寸包含 itemGap) | number | 0 | - |
| showLine | 是否显示层级线 | boolean | false | - |
| itemClass | 节点容器类名 | string | '' | - |
| listClass | 列表容器类名 | string | '' | - |
| scrollDuration | 平滑滚动的默认动画时长(ms) | number | 300 | - |
| smoothMaxDistance | 平滑滚动允许逐帧穿越的最大距离(px),超出部分先瞬跳 | number | 两倍视口 | - |
| scrollbarAutoHideDelay | 滚动条停止滚动多久后淡出(ms),0 表示常驻 | number | 1200 | - |
| scrollbarMinThumbSize | 滑块的最小长度(px) | number | 20 | - |
| keyboard | 是否接管键盘(方向键 / PageUp-Down / Space / Home-End) | boolean | true | - |
| crossScroll | 交叉轴(横向)是否允许原生滚动,关掉即两轴全裁切 | boolean | true | - |
[expand] expandedKeys | 初始展开的节点 key 集合 | TreeNodeKey[] | [] | - |
[expand] defaultExpandAll | 是否默认展开节点 | boolean | false | - |
[expand] expandOnClickNode | 点击节点是否展开(仅在 selectable=false & checkOnClickNode=false 时生效;renderNode 接管整行后不生效) | boolean | false | - |
[checkable] checkable | 是否有 checkbox | boolean | false | - |
[checkable] checkedKeys | 初始勾选的节点 key 集合,只在 checkable 为 true 时生效 | TreeNodeKey[] | [] | - |
[checkable] checkOnClickNode | 点击节点是否可以选中 checkbox | boolean | false | - |
[checkable] checkedStrictly | 是否严格遵循父子不互相关联的做法 | boolean | false | - |
[selectable] selectable | 是否可以选中(renderNode 接管整行后不生效,需自行在 click 里调 toggleSelect) | boolean | false | - |
[selectable] selectedKeys | 初始选中的节点 key 集合,只在 selectable 为 true 时生效 | TreeNodeKey[] | [] | - |
[selectable] selectMultiple | 是否可以多选 | boolean | false | - |
[focus] focusedKeys | 初始激活的节点 key 集合 | TreeNodeKey[] | [] | - |
[draggable] draggable | 是否开启拖拽 | boolean | false | - |
[draggable] dragClass | 拖拽的节点 class | string | '' | - |
[draggable] dragGhostClass | 拖拽的克隆节点 class | string | '' | - |
[draggable] dragoverPlacement | 拖拽区域生效的区域范围 | number[] | [33,66] | - |
[draggable] crossLevelDraggable | 是否允许跨层级拖拽;关掉则只能在同级内换位 | boolean | true | - |
| customGroup | 同级拖拽的分组标识,同组之间才能互拖 | string | - | - |
| filterMethod | 筛选节点的方法,返回 true 显示、false 隐藏 | (query: string, node: TreeNode) => boolean | - | - |
| 其他配置项 | 同 VirtList 配置项 | - | - | - |
渲染函数
对应框架版的插槽。返回 HTMLElement 会被 append 进容器;也可以直接操作最后一个参数 el(容器本身),少一层 DOM 嵌套。
| 名称 | 说明 | 签名 |
|---|---|---|
| renderNode | 整行自定义。库不再画缩进块 / 图标 / 复选框,缩进要自己按 node.level 算 | (node, isExpanded, el) => HTMLElement | void |
| renderContent | 只替换节点内容区,缩进与图标仍由库绘制 | (node, el) => HTMLElement | void |
| renderIcon | 展开图标 | (node, isExpanded, el) => HTMLElement | void |
| renderHeader | 顶部区域(参与滚动) | (el) => HTMLElement | void |
| renderFooter | 底部区域(参与滚动) | (el) => HTMLElement | void |
| renderStickyHeader | 顶部悬浮区域 | (el) => HTMLElement | void |
| renderStickyFooter | 底部悬浮区域 | (el) => HTMLElement | void |
| renderEmpty | 空状态 | (el) => HTMLElement | void |
暴露方法
实例方法,与框架版 ref 上的方法一一对应。
| 方法名 | 说明 | 签名 |
|---|---|---|
| expandAll | 展开/折叠所有节点 | (expanded: boolean) => void |
| expandNode | 展开/折叠指定节点 | (key: TreeNodeKey | TreeNodeKey[], expanded: boolean) => void |
| toggleExpand | 切换节点展开状态 | (node: TreeNode) => void |
| setExpandedKeys | 设置展开的节点 key | (keys: TreeNodeKey[]) => void |
| hasExpanded | 该节点是否展开 | (node: TreeNode) => boolean |
| selectAll | 全选/取消全选 | (selected: boolean) => void |
| selectNode | 选中/取消指定节点 | (key: TreeNodeKey | TreeNodeKey[], selected: boolean) => void |
| toggleSelect | 切换节点选中状态 | (node: TreeNode) => void |
| hasSelected | 该节点是否被选中 | (node: TreeNode) => boolean |
| checkAll | 全部勾选/取消勾选 | (checked: boolean) => void |
| checkNode | 勾选/取消指定节点 | (key: TreeNodeKey | TreeNodeKey[], checked: boolean) => void |
| toggleCheckbox | 切换节点勾选状态 | (node: TreeNode) => void |
| hasChecked | 该节点是否勾选 | (node: TreeNode) => boolean |
| hasIndeterminate | 该节点是否半选 | (node: TreeNode) => boolean |
| getCheckedKeys | 获取已勾选节点的 key | (leafOnly?: boolean) => TreeNodeKey[] |
| getHalfCheckedKeys | 获取半选节点的 key | () => TreeNodeKey[] |
| setFocusedKeys | 设置聚焦节点 | (keys: TreeNodeKey[]) => void |
| hasFocused | 该节点是否聚焦 | (node: TreeNode) => boolean |
| filter | 按查询字符串筛选节点 | (query: string) => void |
| scrollTo | 滚动到(三种意图合一,见下方 VirtTreeScrollTarget) | (target: VirtTreeScrollTarget) => void |
| scrollToKey | 定位到指定节点(折叠时先展开祖先),无论当前是否可见 | (key: TreeNodeKey, options?: VirtScrollOptions) => void |
| scrollKeyIntoView | 把节点滚进可视区域,已完整可见则不动 | (key: TreeNodeKey, options?: VirtScrollOptions) => void |
| scrollToOffset | 滚动到指定偏移量 | (offset: number, options?: VirtScrollOptions) => void |
| scrollToTop | 滚动到顶部 | (options?: VirtScrollOptions) => void |
| scrollToBottom | 滚动到底部 | (options?: VirtScrollOptions) => void |
| scrollFromUser | 上报一次用户发起的滚动 | (offset: number) => void |
| cancelScroll | 取消进行中的平滑滚动动画 | () => void |
| resume | 重挂 DOM 后把内容摆回当前偏移量 | () => void |
| getOffset | 当前偏移量 | () => number |
| getMaxOffset | 当前允许的最大偏移量 | () => number |
| getTotalSize | 内容总尺寸(节点 + 各插槽) | () => number |
| getTreeNode | 根据 key 获取节点 | (key: TreeNodeKey) => TreeNode | undefined |
| setList | 设置新的树数据 | (list: TreeData) => void |
| updateOptions | 增量更新配置项 | (options: Partial<VirtTreeDOMOptions>) => void |
| forceUpdate | 强制更新 | () => void |
| destroy | 销毁实例并解绑所有监听 | () => void |
事件回调
构造函数的第三个参数。键名一律 camelCase。
树相关
| 事件名 | 说明 | 回调参数 |
|---|---|---|
| click | 点击节点(内容区;renderNode 接管后为整行)。与 select / check / 展开互不冲突,先于它们触发,拖拽进行中不触发 | (data: TreeNodeData, node: TreeNode, e: MouseEvent) |
| expand | 展开/折叠节点 | expandKeys: TreeNodeKey[],data:{ node?: TreeNode; expanded: boolean; expandedNodes: TreeNodeData[] } |
| select | 选择节点 | selectedKeys: TreeNodeKey[],data:{ node: TreeNode; selected: boolean; selectedKeys: TreeNodeKey[]; selectedNodes: TreeNodeData[] } |
| check | 勾选节点 | checkedKeys: TreeNodeKey[],data:{ node: TreeNode; checked: boolean; checkedKeys: TreeNodeKey[]; checkedNodes: TreeNodeData[]; halfCheckedKeys: TreeNodeKey[]; halfCheckedNodes: TreeNodeData[] } |
| dragstart | 拖拽开始。sourceNode 是树节点,原始数据在它的 .data 上 | data:{ sourceNode: TreeNode } |
| dragend | 拖拽结束。参数为 undefined 表示被取消(Esc) | data:{ node: TreeNode; prevNode: TreeNode | undefined; parentNode: TreeNode | undefined } | undefined |
滚动相关(由 VirtList 透传)
| 事件名 | 说明 | 回调参数 |
|---|---|---|
| scroll | 滚动 | (event: VirtScrollEvent) |
| offsetChange | 偏移量变化 | (offset: number) |
| toTop | 触顶 | (item: TreeNode) |
| toBottom | 触底 | (item: TreeNode) |
| itemResize | Item 尺寸变化 | (id: string, size: number) |
| update | 渲染列表更新 | (renderList: TreeNode[], state: ListState) |
TreeNode
| 参数名 | 描述 | 类型 | 默认值 |
|---|---|---|---|
| key | 唯一标示 | string | number | - |
| level | 层级 | number | 1 |
| title | 该节点显示的标题 | string | - |
| isLeaf | 是否是叶子节点。动态加载时有效 | boolean | false |
| isLast | 是否是当前层级的最后节点 | boolean | false |
| parent | 父节点引用 | TreeNode | - |
| children | 子节点 | TreeNode[] | - |
| disableSelect | 是否禁用选中 | boolean | false |
| disableCheckbox | 是否禁用复选框 | boolean | false |
| searchedIndex | 筛选匹配下标(-1 表示未匹配) | number | -1 |
| data | 原始数据对象 TreeNodeData | TreeNodeData | - |
TreeFieldNames
| Attribute | Description | Type | Default | Required |
|---|---|---|---|---|
| key | 每个树节点用来作为唯一key的属性 | string, number | key | - |
| title | 指定节点标签为节点对象的某个属性值 | string | title | - |
| children | 指定子树为节点对象的某个属性值 | string | children | - |
| disableSelect | 禁止选中 | string | disableSelect | - |
| disableCheckbox | 禁止复选框勾选 | string | disableCheckbox | - |
| disableDragIn | 禁止拖入该节点 | string | disableDragIn | - |
| disableDragOut | 禁止拖出该节点 | string | disableDragOut | - |
VirtTreeScrollTarget
scrollTo 的参数。它在 VirtScrollOptions 的基础上加了 key / offset,并把 align 扩出一个 nearest:
| Attribute | Description | Type | Default |
|---|---|---|---|
| key | 目标节点 key。节点被折叠时会先展开它的祖先 | TreeNodeKey | - |
| offset | 偏移量(≥ 0 时优先于 key) | number | - |
| align | 对齐方式。nearest:已完整可见就不动,否则滚到最近的那条边;start:顶部对齐视口顶部;end:底部对齐视口底部 | 'start' | 'end' | 'nearest' | nearest |
| behavior | 滚动方式,smooth 为平滑动画 | 'auto' | 'smooth' | auto |
| duration | 平滑动画时长(ms),缺省取 scrollDuration | number | - |
| maxDistance | 本次逐帧穿越的最大距离(px),超出部分先瞬跳 | number | 两倍视口 |
| onDone | 动画结束回调,canceled 表示被中断 | (canceled: boolean) => void | - |
通常用直接方法更好读
scrollTo 把三种意图收在一个入口里,拼参数往往不如直接调用清楚: scrollToOffset(offset, options?) / scrollToKey(key, options?) / scrollKeyIntoView(key, options?)。三者的 options 都是标准的 VirtScrollOptions, align 只有 start / end。
样式与主题
树组件的默认样式随各包的 style.css 一起交付,需要手动引一次(与滚动条样式同一份):
import '@virt-list/vue/style.css'; // 换成你装的那个包组件的 JS 里刻意不 import 这份 css:那会让整个包在纯 Node 环境(SSR)下 import 不了 ——Node 不认 .css 扩展名。
所有可定制项都通过 CSS 变量暴露,覆盖变量即可换肤,不需要与选择器优先级搏斗。
暗色模式
样式内置两套令牌,命中以下任一条件即切换为暗色:
<html>上带有darkclass(VitePress、大多数文档站与后台框架的约定);- 任意祖先元素上带有
data-theme="dark"。
// 自行控制时,只需切换根节点的 class
document.documentElement.classList.toggle('dark', isDark);如果你的项目使用别的主题标记(例如 body[theme='night']),直接在该选择器下覆盖变量即可:
body[theme='night'] .virt-tree-item {
--virt-tree-color-text: rgb(255 255 255 / 87%);
--virt-tree-color-node-bg-hover: rgb(235 235 245 / 8%);
--virt-tree-line-color: #3c3f46;
}可用变量
变量定义在 .virt-tree-item 与 .virt-tree-all-drag-area 上,覆盖时请使用同一层级或更高优先级的选择器。
| 变量 | 说明 | 亮色默认值 | 暗色默认值 |
|---|---|---|---|
--virt-tree-color-text | 节点文字 | #1f2329 | rgb(255 255 255 / 87%) |
--virt-tree-color-text-selected | 选中态文字 | #1f52d6 | #8fb2ff |
--virt-tree-color-text-disabled | 禁用态文字 | #a8abb2 | rgb(235 235 245 / 38%) |
--virt-tree-color-node-bg | 节点背景(默认透明,跟随容器) | transparent | transparent |
--virt-tree-color-node-bg-hover | 悬停背景 | rgb(31 35 41 / 6%) | rgb(235 235 245 / 8%) |
--virt-tree-color-node-bg-selected | 选中背景 | rgb(42 99 240 / 10%) | rgb(97 143 250 / 20%) |
--virt-tree-color-node-bg-disabled | 禁用背景 | transparent | transparent |
--virt-tree-color-node-bg-focused | 聚焦背景 | rgb(42 99 240 / 6%) | rgb(97 143 250 / 10%) |
--virt-tree-color-node-ring-focused | 聚焦描边环 | rgb(42 99 240 / 55%) | rgb(140 175 255 / 65%) |
--virt-tree-color-icon | 展开箭头颜色 | #5f6672 | rgb(235 235 245 / 60%) |
--virt-tree-color-icon-bg-hover | 展开箭头悬停底色 | rgb(31 35 41 / 10%) | rgb(235 235 245 / 14%) |
--virt-tree-line-color | 层级连接线 | #d6d9dd | #3c3f46 |
--virt-tree-color-checkbox-bg | 复选框底色 | #fff | transparent |
--virt-tree-color-checkbox-bg-checked | 勾选底色 | #2a63f0 | #3970e4 |
--virt-tree-color-checkbox-bg-indeterminate | 半选底色 | #2a63f0 | #3970e4 |
--virt-tree-color-checkbox-bg-disabled | 禁用底色 | #f2f3f5 | rgb(235 235 245 / 8%) |
--virt-tree-color-checkbox-border | 复选框描边 | #c4c7ce | #55575e |
--virt-tree-color-checkbox-border-hover | 复选框悬停描边 | #2a63f0 | #5a8dfb |
--virt-tree-color-checkbox-border-checked | 勾选描边 | #2a63f0 | #3970e4 |
--virt-tree-color-checkbox-border-indeterminate | 半选描边 | #2a63f0 | #3970e4 |
--virt-tree-color-checkbox-border-disabled | 禁用描边 | #dcdfe4 | #3a3b41 |
--virt-tree-color-checkbox-mark | 勾/横杠颜色 | #fff | #fff |
--virt-tree-color-drag-line | 拖拽指示线 | #2a63f0 | #5a8dfb |
--virt-tree-color-drag-box | 拖入节点内的高亮框底色 | rgb(42 99 240 / 8%) | rgb(97 143 250 / 14%) |
--virt-tree-color-drag-line-disabled | 不可放置时的指示线 | rgb(42 99 240 / 40%) | rgb(97 143 250 / 40%) |
--virt-tree-color-allow-drag-area-bg | 可放置区域底色 | rgb(42 99 240 / 8%) | rgb(97 143 250 / 12%) |
--virt-tree-color-allow-drag-area-bd | 可放置区域描边 | rgb(42 99 240 / 45%) | rgb(97 143 250 / 50%) |
--virt-tree-color-bg-clone-node | 拖拽跟随副本底色 | #fff | #26272d |
--virt-tree-node-radius | 节点圆角 | 6px | 同亮色 |
--virt-tree-icon-radius | 箭头悬停底色圆角 | 4px | 同亮色 |
--virt-tree-checkbox-size | 复选框尺寸 | 16px | 同亮色 |
--virt-tree-checkbox-radius | 复选框圆角 | 4px | 同亮色 |
--virt-tree-duration | 过渡时长 | 160ms | 同亮色 |
--virt-tree-ease | 过渡曲线 | cubic-bezier(0.4, 0, 0.2, 1) | 同亮色 |
--virt-tree-switcher-icon-margin-right | 箭头右间距(同时影响拖拽线左偏移) | 4px | 同亮色 |
--virt-tree-drag-line-gap | 跨层级拖拽线的分段间隔 | 4px | 同亮色 |
状态 class
库会在节点上切换以下 class,可直接用于自定义样式:
| class | 元素 | 含义 |
|---|---|---|
is-selected | .virt-tree-node | 已选中 |
is-focused | .virt-tree-node | 已聚焦 |
is-disabled | .virt-tree-node | 禁止选中 |
is-expanded | .virt-tree-icon-wrapper | 已展开 |
is-checked | .virt-tree-checkbox | 已勾选 |
is-indeterminate | .virt-tree-checkbox | 半选 |
is-dragging | .virt-list__client | 拖拽进行中 |
/* 例:换成品牌绿,并放大节点圆角 */
.virt-tree-item {
--virt-tree-color-text-selected: #12854a;
--virt-tree-color-node-bg-selected: rgb(24 160 88 / 12%);
--virt-tree-color-checkbox-bg-checked: #18a058;
--virt-tree-color-checkbox-border-checked: #18a058;
--virt-tree-node-radius: 10px;
}减少动效
样式已适配 prefers-reduced-motion: reduce,系统开启「减弱动态效果」时会自动关闭箭头旋转、勾选与背景过渡动画。