el-tree 高级用法、性能优化与定制化el-tree 的核心功能: el-tree 是 Element Plus 提供的一个功能丰富的树形组件,支持数据展示、节点选择、懒加载、自定义模板等多种功能,能够满足绝大多数树形结构数据的展示需求。el-tree-v2 提供了虚拟滚动(virtual scrolling)功能,显著提升了渲染性能,避免了传统树形组件在处理大数据时的卡顿问题。el-tree 提供了 render-content 和 scoped slot 两种方式来定制节点内容,同时可以结合 el-select 封装出 el-tree-select 这样的复合组件,满足更复杂的交互需求。在现代前端开发中,树形结构(Tree)是一种非常常见且重要的数据组织形式,广泛应用于文件系统、组织架构、菜单导航、权限管理等场景。Element Plus 作为 Vue 3 生态中流行的 UI 组件库,提供了功能强大且易于使用的 el-tree 组件,用于展示和操作树形数据。本文将深入探讨如何高效地封装 el-tree 组件,包括其核心功能、高级用法、性能优化、以及如何结合其他 Element Plus 组件进行创新封装。
el-tree 组件概述在数据结构中,树是一种层次化的数据结构,由节点(node)和边(edge)组成。它模拟了自然界中树的结构,其中有一个根节点(root),每个节点可以有零个或多个子节点(children),形成一个分支结构。树形结构因其高效的搜索和数据检索能力而广泛应用于计算机科学。例如,文件系统就是一个典型的树形结构,每个文件夹是一个节点,包含文件或子文件夹。
图1: UI 视觉树结构示例,展示了组件的层次关系。
el-tree 组件el-tree 是 Element Plus 提供的一个 Vue 3 组件,用于以树形结构展示数据。它支持多种特性,使其在处理复杂数据时非常灵活和强大:
data 属性绑定树形数据,每个节点包含 label(显示文本)和 children(子节点数组)等属性。show-checkbox 属性开启)。lazy 属性),按需加载子节点数据,提高初始渲染性能。default-expanded-keys 和 default-checked-keys 属性设置初始展开或选中的节点。render-content 或 scoped slot 自定义每个树节点的显示内容。使用 el-tree 最基本的方式是传入一个数组作为其 data 属性。每个数组元素代表一个根节点,并且可以包含一个 children 数组来表示其子节点,形成嵌套的树形结构。props 属性用于配置节点数据的字段名映射,例如 label 对应节点显示的文本,children 对应子节点数组。
<template>
<el-tree :data="treeData" :props="defaultProps" @node-click="handleNodeClick" />
</template>
<script lang="ts" setup>
import { ref } from 'vue';
interface Tree {
label: string;
children?: Tree[];
}
const handleNodeClick = (data: Tree) => {
console.log(data);
};
const treeData: Tree[] = [
{
label: 'Level one 1',
children: [
{
label: 'Level two 1-1',
children: [{ label: 'Level three 1-1-1' }],
},
],
},
{
label: 'Level one 2',
children: [
{ label: 'Level two 2-1' },
{ label: 'Level two 2-2' },
],
},
];
const defaultProps = {
children: 'children',
label: 'label',
};
</script>
在这个示例中,treeData 定义了树的结构,defaultProps 告诉 el-tree 如何解析数据。@node-click 事件则可以在节点被点击时触发。
el-tree 支持复选框选择功能,通过设置 show-checkbox 属性为 true 即可启用。同时,可以通过 node-key 属性指定一个唯一标识符来方便地获取和设置选中节点。Element Plus 提供了 getCheckedNodes 和 getCheckedKeys 等方法来获取当前选中的节点数据或其对应的键,以及 setCheckedNodes 和 setCheckedKeys 来设置选中状态。
<template>
<el-tree
ref="treeRef"
:data="data"
show-checkbox
default-expand-all
node-key="id"
highlight-current
:props="defaultProps"
/>
<div class="mt-2">
<el-button @click="getCheckedNodes">获取选中节点</el-button>
<el-button @click="setCheckedKeys">设置选中键</el-button>
</div>
</template>
<script lang="ts" setup>
import { ref } from 'vue';
import type { TreeInstance } from 'element-plus';
const treeRef = ref<TreeInstance>();
const data = [
{ id: 1, label: 'Level one 1', children: [{ id: 4, label: 'Level two 1-1' }] },
{ id: 2, label: 'Level one 2', children: [{ id: 5, label: 'Level two 2-1' }] },
];
const defaultProps = {
children: 'children',
label: 'label',
};
const getCheckedNodes = () => {
console.log(treeRef.value!.getCheckedNodes(false, false));
};
const setCheckedKeys = () => {
treeRef.value!.setCheckedKeys([5]);
};
</script>
对于节点数量庞大的树形结构,一次性加载所有数据可能导致性能问题。el-tree 支持懒加载模式,通过设置 lazy 属性为 true 和提供 load 方法,可以在节点展开时异步加载其子节点数据。load 方法接收当前节点和 resolve 函数作为参数,当数据加载完成后,调用 resolve 并传入子节点数据。
<template>
<el-tree :props="props" :load="loadNode" lazy show-checkbox />
</template>
<script lang="ts" setup>
import type Node from 'element-plus/es/components/tree/src/model/node';
interface Tree {
name: string;
leaf?: boolean;
}
const props = {
label: 'name',
children: 'zones',
isLeaf: 'leaf',
};
const loadNode = (node: Node, resolve: (data: Tree[]) => void) => {
if (node.level === 0) {
return resolve([{ name: 'Root 1' }, { name: 'Root 2' }]);
}
if (node.level > 1) return resolve([]);
setTimeout(() => {
const data: Tree[] = [
{ name: 'Leaf node', leaf: true },
{ name: 'Parent node' },
];
resolve(data);
}, 500);
};
</script>
此功能对于优化用户体验,特别是当树形数据深度大、广度大时,尤为重要。
el-tree-v2 虚拟化树当树形结构包含大量节点时,DOM 元素的过多渲染会导致页面卡顿。Element Plus 提供了 el-tree-v2 组件,专门用于解决这个问题。el-tree-v2 基于虚拟滚动技术,只渲染可见区域的节点,从而实现“闪电般”的滚动性能,即使面对海量数据也能保持流畅。
图2: 大型树形结构示意图,提示虚拟化的重要性。
el-tree-v2 的优势el-tree 保持了高度一致性,降低了学习成本。el-tree-v2使用 el-tree-v2 时,需要额外指定 height 属性来确定组件的可见高度,以便虚拟滚动功能能够正常工作。
<template>
<el-tree-v2 :data="data" :props="props" :height="208" />
</template>
<script lang="ts" setup>
interface Tree {
id: string;
label: string;
children?: Tree[];
}
const getKey = (prefix: string, id: number) => <code>${prefix}-${id};
const createData = (
maxDeep: number,
maxChildren: number,
minNodesNumber: number,
deep = 1,
key = 'node'
): Tree[] => {
let id = 0;
return Array.from({ length: minNodesNumber })
.fill(deep)
.map(() => {
const childrenNumber = deep === maxDeep ? 0 : Math.round(Math.random() * maxChildren);
const nodeKey = getKey(key, ++id);
return {
id: nodeKey,
label: nodeKey,
children: childrenNumber ? createData(maxDeep, maxChildren, childrenNumber, deep + 1, nodeKey) : undefined,
};
});
};
const props = {
value: 'id',
label: 'label',
children: 'children',
};
const data = createData(4, 30, 40); // 创建大量模拟数据
</script>
这个示例展示了如何创建大量数据并将其绑定到 el-tree-v2,通过设置 height,组件将自动启用虚拟滚动。
el-tree-select 与 el-tree-transferel-tree-select:树形选择器el-tree-select 是 el-select 和 el-tree 组件的结合,提供了一个带有树形下拉菜单的选择器。这在需要从层级数据中选择一个或多个项的场景中非常有用。例如,选择组织结构中的某个部门,或者一个分类体系中的某个类别。
视频:Element Vue 基础介绍,了解 Element UI 组件库。
el-tree-select 继承了 el-tree 和 el-select 的所有属性、方法、事件和插槽,这意味着它具有高度的灵活性和可定制性,例如支持懒加载、自定义选项内容等。使用时,开发者只需要传入数据和相关配置即可。
<template>
<el-tree-select v-model="value" :data="data" style="width: 240px" />
</template>
<script lang="ts" setup>
import { ref } from 'vue';
const value = ref();
const data = [
{
value: '1',
label: 'Branch 1',
children: [
{ value: '1-1', label: 'Leaf 1-1' },
{ value: '1-2', label: 'Leaf 1-2' },
],
},
{ value: '2', label: 'Branch 2' },
];
</script>
el-tree-transfer:树形穿梭框el-tree-transfer 结合了树形结构和穿梭框的功能,常用于权限分配、角色管理等场景,允许用户在两个树形结构之间进行节点的移动。这种组件通常提供了搜索、全选、反选等功能,极大地提升了用户在复杂层级数据操作时的效率。
图3: el-tree-transfer 组件示例,用于在两个树形结构之间穿梭数据。
虽然 el-tree-transfer 不是 Element Plus 的原生组件,但社区有许多基于 Element UI 封装的优秀实现,例如 el-tree-transfer,它们提供了方便的 API 来实现树形数据在两边的穿梭操作。
el-tree 组件能力评估为了更好地理解 el-tree 的综合能力,我们可以对其进行一个雷达图评估。这个评估将从数据承载、交互性、可定制性、性能和易用性五个维度进行考量。
图4: el-tree 组件能力雷达图
从雷达图可以看出,标准版 el-tree 在易用性、交互性和可定制性方面表现出色,能够满足日常大部分需求。但在数据承载和性能方面,面对海量数据时可能会遇到瓶颈。而 el-tree-v2 则在数据承载和性能方面进行了显著优化,使其成为处理大数据量树形结构的理想选择,虽然在可定制性上可能略有简化以保证性能。
可以通过设置 highlight-current 属性为 true 来高亮当前选中的节点。如果需要通过代码动态高亮特定节点,可以使用 setCurrentKey 或 setCurrentNode 方法来设置当前节点。此外,也可以通过 CSS 和 JavaScript 来手动为节点添加或移除类名,以实现自定义的高亮样式。
el-tree 如何处理大量数据导致的性能问题?
对于大量数据,推荐使用 el-tree-v2 组件。el-tree-v2 引入了虚拟滚动技术,只渲染可视区域内的节点,从而极大地优化了性能。对于标准 el-tree,可以通过懒加载(lazy 和 load 属性)来按需加载子节点,避免一次性渲染所有数据。
el-tree 中选中的节点?
可以通过 ref 获取 el-tree 实例,然后调用其提供的方法:
getCheckedNodes(leafOnly, includeHalfChecked):获取选中且处于叶子节点的节点。getCheckedKeys(leafOnly):获取选中节点的 key 数组。setCheckedNodes(nodes, checked):通过节点数据设置选中状态。setCheckedKeys(keys, checked):通过节点的 key 设置选中状态。setChecked(data, checked, deep):设置某个节点的选中状态。使用这些方法时,需要确保 node-key 属性已正确配置。
el-tree 节点的显示内容?
el-tree 提供了两种方式来定制节点内容:
render-content 属性: 传入一个渲染函数,该函数返回节点内容的 VNode。scoped slot: 使用 #default="{ node, data }" 具名插槽,可以在模板中直接编写自定义的节点内容,其中 node 是当前节点的 TreeNode 对象,data 是节点的数据。通常情况下,使用 scoped slot 会更具可读性和易维护性。
Element Plus 的 el-tree 组件及其虚拟化版本 el-tree-v2 为 Vue 3 应用程序中的树形数据展示和交互提供了强大而灵活的解决方案。通过深入理解其基本用法、懒加载、节点选择以及性能优化策略,开发者可以构建出高效、用户友好的树形界面。此外,结合 el-select 等其他组件进行创新封装,能够满足更复杂的业务需求,进一步提升开发效率和用户体验。