
Element Plus Tree V2 虚拟化树组件完整指南海量数据下的高性能树形视图【免费下载链接】element-plus A Vue.js 3 UI Library made by Element team项目地址: https://gitcode.com/GitHub_Trending/el/element-plus导读Element Plus 在常规 Tree 组件之外提供了基于虚拟列表Virtual List实现的 Tree V2 组件即使面对数万乃至十万级的节点数据也能保持流畅的滚动性能与稳定的渲染开销。本文以 tree-v2 官方文档 为主体结合 Element Plus 仓库内 Tree V2 的源码packages/components/tree-v2与全部官方示例docs/examples/tree-v2系统讲解 Tree V2 的接入方式、选择与勾选语义、默认展开/选中、节点内容与样式定制、过滤方法以及完整的 Attributes、props、Exposes、Events、Slots 和 TypeScript 类型声明帮助你在超大树形数据场景下正确选型并落地实现。注意Tree V2 目前仍标记为beta状态在使用前请结合自身项目评估稳定性要求。为什么需要 Tree V2虚拟化原理传统 Tree 组件会为每一个节点渲染对应的 DOM 元素当数据量达到数千、数万节点时DOM 数量爆炸会直接导致首屏卡顿与交互延迟。Tree V2 的核心思路是只渲染可视区域内的节点无论整棵树有多少节点页面中同时存在的行数仅由可视高度决定滚动时通过虚拟列表的窗口计算动态复用行从而实现“对任意数据量都有飞速滚动性能”官方定位Tree view with blazing fast scrolling performance for any amount of data。从源码看Tree V2 将节点数据结构化地组织在内存中types.ts 中的Tree接口使用treeNodeMapMapTreeKey, TreeNode按 key 索引节点、levelTreeNodeMapMapnumber, TreeNode[]按层级分组节点、treeNodes保存扁平化后的渲染列表虚拟列表正是基于这份扁平化列表按窗口切片渲染。组件还提供perfMode性能模式默认开启配置项——源码注释指出性能模式会增加内存占用但滚动更平滑见 virtual-tree.ts属于典型的“以内存换渲染性能”的取舍。基础用法快速接入一棵虚拟树Tree V2 的基础用法与 Tree 非常接近传入data树形数据、props字段映射与height树高度即可。以下为基础示例来自官方示例 basic.vuetemplate el-tree-v2 stylemax-width: 600px :datadata :propsprops :height200 / /template script langts setup interface Tree { id: string label: string children?: Tree[] } const props { value: id, // 唯一标识字段名 label: label, // 显示文本字段名 children: children, // 子节点字段名 } const data [ { id: node-1, label: Level one 1, children: [ { id: node-1-1, label: Level two 1-1 }, { id: node-1-2, label: Level two 1-2 }, ], }, { id: node-2, label: Level one 2, }, ] /script要点说明height是必填的关键参数它决定了虚拟列表的可视窗口高度。源码中height的默认值为200见 virtual-tree.ts当节点总数远超可视行数时虚拟化的收益最明显。props默认值即使不传props组件也会使用内置默认字段名。源码中props的默认配置为{ children: children, label: label, disabled: disabled, value: id, class: }见 virtual-tree.ts 与TreeOptionsEnum枚举定义。value字段必须全局唯一它作为节点的 key驱动treeNodeMap的索引与default-expanded-keys、default-checked-keys、setCheckedKeys等基于 key 的 API 工作重复会导致节点状态错乱。勾选模式Selectable、check-on-click 与禁用开启复选框设置show-checkbox后每个节点前会出现复选框官方示例 selectable.vueel-tree-v2 stylemax-width: 600px :datadata :propsprops show-checkbox :height200 /默认情况下父子节点的勾选状态会级联联动勾选父节点会同时勾选全部子节点勾选子节点时父节点自动进入半选indeterminate状态。若希望父子勾选互不影响设置check-strictly为true即可——源码注释明确说明该属性含义为“当show-checkbox为true时节点勾选状态不影响其父节点与子节点”见 virtual-tree.ts。点击行为的三个开关Tree V2 将「点击节点」与「展开/勾选」解耦为三个独立开关属性默认值说明expand-on-click-nodetrue点击节点是否展开/收起设为false后只有点击箭头图标才展开check-on-click-nodefalse点击节点是否勾选/取消勾选保持false时只能通过复选框勾选check-on-click-leaftrue点击叶子节点最后一个子级是否勾选/取消勾选这三个开关可以在源码 virtual-tree.ts 中逐一对应到 props 定义。⚠️ 官方警告当使用show-checkbox时由于check-on-click-leaf默认为true树的最后一级子节点可以通过点击节点本身被勾选。若你希望只有复选框能控制勾选请显式设置:check-on-click-leaffalse。禁用节点的复选框通过props.disabled声明数据中表示禁用状态的字段名再将部分节点对应字段设为true即可让这些节点的复选框禁用、不可点击官方示例 disabled.vueinterface Tree { id: string label: string children?: Tree[] disabled: boolean } const props { value: id, label: label, children: children, disabled: disabled, // 声明 disabled 字段 } // 生成数据时按条件置位 const data /* ... */ { id: node-2, label: node-2, disabled: true, // 该节点复选框被禁用 }值得留意的是源码中的TreeNode接口专门定义了isEffectivelyChecked字段其注释详述了「有效勾选」的递归判定规则禁用叶子节点始终被视为已勾选、非禁用叶子节点反映其真实勾选状态、非叶子节点仅当所有子节点均“有效勾选”时才视为已勾选见 types.ts。这意味着禁用节点不会破坏父子勾选级联的统计正确性。默认展开与默认勾选通过default-expanded-keys与default-checked-keys可以分别指定初始化时展开的节点 key 数组与初始化时勾选的节点 key 数组官方示例 default-state.vueel-tree-v2 stylemax-width: 600px :datadata :height200 :propsprops show-checkbox :default-checked-keysdefaultCheckedKeys :default-expanded-keysdefaultExpandedKeys /// 动态取第一个有子节点的节点作为默认展开/勾选目标 const data createData(4, 30, 40) const checkedKeys: string[] [] const expandedKeys: string[] [] for (const datum of data) { const children datum.children if (children) { expandedKeys.push(datum.id) checkedKeys.push(children[0].id) break } } const defaultCheckedKeys ref(checkedKeys) const defaultExpandedKeys ref(expandedKeys)官方示例在script setup中通过ref()包裹 key 数组运行时也可动态调整这两个数组来更新树的初始化状态。两个属性的类型均为Arraystring | number对应源码中defaultCheckedKeys与defaultExpandedKeys的TreeKey[]定义见 types.ts。自定义节点内容default 插槽Tree V2 通过默认插槽default slot暴露{ node, data }作用域其中node是 TreeNode 类型实例包含key、level、parent、children、data、disabled、label、isLeaf、expanded等字段。你可以在插槽中自由组合图标、按钮与任意内容官方示例 custom-node.vueel-tree-v2 stylemax-width: 600px :datadata :propsprops :height200 template #default{ node } el-icon classel-icon--left Document v-ifnode.isLeaf / Folder v-else-if!node.expanded / FolderOpened v-else / /el-icon span classprefix :class{ is-leaf: node.isLeaf }[ElementPlus]/span span{{ node.label }}/span /template /el-tree-v2插槽中利用node.isLeaf判断叶子节点、node.expanded判断展开状态即可渲染「文档 / 关闭的文件夹 / 打开的文件夹」三类图标实现文件管理器中常见的视觉反馈。自定义节点类名与图标自定义节点类名2.9.0props.class支持字符串或函数形式函数签名为(data: TreeNodeData, node: TreeNode) string | { [key: string]: boolean }可依据节点数据动态返回类名官方示例 custom-node-class.vueimport type { TreeNode, TreeNodeData } from element-plus // 根据数据标记动态返回类名 const customNodeClass ({ isPenultimate }: TreeNodeData, node: TreeNode) isPenultimate ? is-penultimate : el-tree-v2 stylemax-width: 600px :datadata show-checkbox :expand-on-click-nodefalse :props{ class: customNodeClass } //* 注意类名挂在节点行上需要 :deep() 穿透到内部元素 */ :deep(.is-penultimate .el-tree-node__label) { color: #626aef; font-weight: 600; }对应源码中TreeOptionProps.class的联合类型定义string | ((data, node) string | { [key: string]: boolean })可在 types.ts 查证。注意示例同时设置了:expand-on-click-nodefalse演示了“只点箭头展开”的交互模式。自定义节点图标2.10.3与 2.9.0 的自定义节点内容不同icon属性允许你传入一个图标组件作为默认展开/收起指示器同时插槽中node.expanded与node.isLeaf两个属性可以支撑更细粒度的图标切换官方示例 custom-icon.vueel-tree-v2 stylemax-width: 600px :datadata :propsprops :height200 template #default{ node } el-icon classnode-icon :class{ is-leaf: node.isLeaf } Document v-ifnode.isLeaf / Folder v-else-if!node.expanded / FolderOpened v-else / /el-icon span{{ node.label }}/span /template /el-tree-v2三种状态叶子 / 展开 / 折叠分别渲染不同图标并在.node-icon.is-leaf场景下用 CSS 变量--el-color-warning调整配色实现与icon属性类型为string | Component互补的自定义能力。节点过滤filter 方法与 filter-method从 2.9.1 起filter-method支持接收第三个参数node。过滤流程为调用 Tree 实例的filter(query)方法传入关键词组件对每个节点执行filter-method(query, data, node)返回false的节点会被隐藏官方示例 filter.vuetemplate el-input v-modelquery stylewidth: 240px placeholderPlease enter keyword inputonQueryChanged / el-tree-v2 reftreeRef stylemax-width: 600px :datadata :propsprops :filter-methodfilterMethod :height200 / /template script langts setup import { ref } from vue import type { TreeNodeData, TreeV2Instance } from element-plus const query ref() const treeRef refTreeV2Instance() const onQueryChanged (query: string) { treeRef.value!.filter(query) } // 注意这里只用到 (query, node) 两个参数2.9.1 可接收 (query, data, node) const filterMethod (query: string, node: TreeNodeData) node.label!.includes(query) /script源码层面过滤逻辑位于 useFilter.tsfilterable计算属性通过isFunction(props.filterMethod)判断是否已配置过滤方法未配置时调用filter会直接返回配置后对每个节点执行filter?.(query, node.data, node)。文件头注释也明确提示“当数据量非常大时使用 filter 会造成卡顿”见 useFilter.ts因此在超大树上做高频过滤如每次输入即过滤需要自行评估性能。filter-method的完整签名见 types.ts 中的FilterMethod类型(query: string, data: TreeNodeData, node: TreeNode) boolean。TreeV2 API 全量速查以下 API 表格与官方文档保持一致并补充了源码级默认值与类型佐证。TreeV2 Attributes名称说明类型默认值源码佐证data树数据Array{[key: string]: any}—virtual-tree.tsempty-text数据为空时显示的文本string—同上props配置选项见下表object见 props 表virtual-tree.tshighlight-current当前节点是否高亮booleanfalsevirtual-tree.tsexpand-on-click-node点击节点是否展开/收起为false时仅点击箭头图标展开/收起booleantruevirtual-tree.tscheck-on-click-node点击节点是否勾选/取消勾选为false时仅能通过复选框勾选booleanfalsevirtual-tree.tscheck-on-click-leaf(2.9.6)点击叶子节点最后一级子级是否勾选/取消勾选booleantruevirtual-tree.tsdefault-expanded-keys默认展开节点的 key 数组Arraystring \| number—types.tsshow-checkbox节点是否可勾选显示复选框booleanfalsevirtual-tree.tscheck-strictly为true时节点勾选状态不影响父/子节点booleanfalsevirtual-tree.tsdefault-checked-keys默认勾选节点的 key 数组Arraystring \| number—types.tscurrent-node-key初始选中节点的 keystring \| number—virtual-tree.tsfilter-method过滤方法返回false时隐藏节点(query: string, data: TreeNodeData, node: TreeNode) boolean—types.tsindent相邻层级节点的水平缩进像素number16virtual-tree.tsicon自定义树节点图标组件string \| Component—virtual-tree.tsitem-size(2.2.33)自定义树节点行高number26virtual-tree.tsscrollbar-always-on(2.10.4)是否始终显示滚动条booleanfalsevirtual-tree.tsheight树的高度number200virtual-tree.ts另外源码中还存在两个文档表格之外的属性accordion手风琴模式源码标注“需要优化”见 virtual-tree.ts与perfMode性能模式默认true开启后更平滑但更耗内存见 virtual-tree.ts可作为进阶配置参考。props字段映射配置属性说明类型默认值value节点唯一标识字段名值必须全树唯一stringidlabel指定节点对象的哪个字段作为显示文本stringlabelchildren指定节点对象的哪个字段作为子树stringchildrendisabled指定节点对象的哪个字段表示复选框禁用stringdisabledclass(2.9.0)自定义节点类名string \| (data: TreeNodeData, node: TreeNode) string \| {[key: string]: boolean}—上述默认值定义在 virtual-tree.ts 的TreeOptionsEnum中KEY id、LABEL label、CHILDREN children、DISABLED disabled、CLASS 。TreeV2 Exposes实例方法组件通过ref暴露以下方法其中TreeKey string | number方法说明参数filter过滤所有节点被过滤的节点隐藏(query: string)getCheckedNodes返回当前勾选的节点数组需show-checkbox为true(leafOnly: boolean)getCheckedKeys返回当前勾选节点的 key 数组(leafOnly: boolean)setCheckedKeys将指定 keys 对应的节点设为勾选(keys: TreeKey[])setChecked设置节点是否勾选deep2.14.0表示是否递归勾选/取消子节点(key: TreeKey, checked: boolean, deep?: boolean)setExpandedKeys将指定 keys 对应的节点展开(keys: TreeKey[])getHalfCheckedNodes返回当前半选节点数组—getHalfCheckedKeys返回当前半选节点的 key 数组—getCurrentKey返回高亮节点的 key无高亮时为undefined—getCurrentNode返回高亮节点的数据无高亮时为undefined—setCurrentKey按 key 设置高亮节点(key: TreeKey)getNode按 key 或数据获取节点(data: TreeKey \| TreeNodeData)expandNode展开指定节点(node: TreeNode)collapseNode收起指定节点(node: TreeNode)setData重置树数据当数据量极大时响应式数据会造成性能下降可用此方法规避(data: TreeData)scrollTo(2.8.0)滚动到指定偏移位置(offset: number)scrollToNode(2.8.0)按指定滚动策略滚动到指定 key 的节点(key: TreeKey, strategy?: auto \| smart \| center \| start \| end)其中setData是 Tree V2 面向超大数据的关键性能 API官方说明指出“当数据非常大时使用响应式数据会导致性能不佳因此我们提供了一种规避方式”见 docs/en-US/component/tree-v2.md。若你的数据是频繁整体替换如分页/异步加载优先用setData而非直接改写data的响应式引用。TreeV2 Events名称说明参数node-click点击节点时触发(data: TreeNodeData, node: TreeNode, e: MouseEvent)node-drop(2.8.3)拖拽内容放置到节点上时触发(data: TreeNodeData, node: TreeNode, e: DragEvent)node-contextmenu右键点击节点时触发(e: Event, data: TreeNodeData, node: TreeNode)check-change节点勾选状态改变时触发(data: TreeNodeData, checked: boolean)check点击节点复选框后触发(data: TreeNodeData, info: { checkedKeys: TreeKey[], checkedNodes: TreeData, halfCheckedKeys: TreeKey[], halfCheckedNodes: TreeData })current-change当前节点变化时触发(data: TreeNodeData, node: TreeNode)node-expand节点展开时触发(data: TreeNodeData, node: TreeNode)node-collapse节点收起时触发(data: TreeNodeData, node: TreeNode)事件名与参数校验器在源码 virtual-tree.ts 的treeEmits中统一定义其中check事件的info对象正是 types.ts 中的CheckedInfo类型。TreeV2 Slots名称说明类型default自定义节点内容{ node: TreeNode, data: TreeNodeData }empty(2.9.0)数据为空时的自定义内容—TypeScript 类型声明Tree V2 的类型定义集中在 types.ts官方文档也提供了完整声明见 docs/en-US/component/tree-v2.mdtype TreeNodeData Recordstring, any type TreeKey string | number type TreeData TreeNodeData[] interface TreeNode { key: TreeKey level: number parent?: TreeNode children?: TreeNode[] data: TreeNodeData disabled?: boolean label?: string isLeaf?: boolean expanded?: boolean isEffectivelyChecked?: boolean }实际源码中TreeNode还包含更多字段parent指向父节点、level表示层级根节点为 1、isEffectivelyChecked用于级联勾选语义的递归判定见 types.ts。在script setup中可通过import type { TreeNode, TreeNodeData, TreeV2Instance } from element-plus直接获得类型提示示例可参考 custom-node-class.vue 与 filter.vue。进一步探索源码与测试组件主入口packages/components/tree-v2/index.ts组件注册与导出、tree.vue 与 tree-node.vue渲染与交互实现组合式逻辑useTree.ts树构建、useCheck.ts勾选/半选状态、useFilter.ts过滤单元测试packages/components/tree-v2/tests/tree.test.ts官方示例全集docs/examples/tree-v2basic、selectable、disabled、default-state、custom-node、custom-node-class、custom-icon、filter 共 8 个可运行示例SSR 用例ssr-testing/cases/tree-v2.vue总结与选型建议Tree V2 是 Element Plus 面向“海量树形数据”给出的高性能答案通过虚拟列表只渲染可视行配合内存化的treeNodeMap与按层级的levelTreeNodeMap索引在数据量达到数万级时依然保持流畅滚动。使用时应把握以下关键点必配height否则虚拟窗口无法计算value字段全局唯一它是所有 key 类 API展开、勾选、滚动到节点的地基理解expand-on-click-node、check-on-click-node、check-on-click-leaf三者组合特别是默认check-on-click-leaf: true带来的“点击叶子即勾选”行为数据整体替换场景优先使用setData规避响应式开销超大数据下的filter过滤存在性能代价高频过滤需自行评估或做防抖处理。若你的数据量在几百到几千级、交互以单选和拖拽为主常规 Tree 组件文档 可能更合适当数据规模成为渲染瓶颈时再切换到 Tree V2 即可获得数量级层面的渲染性能提升。【免费下载链接】element-plus A Vue.js 3 UI Library made by Element team项目地址: https://gitcode.com/GitHub_Trending/el/element-plus创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考