Tree V2 虚拟化树形控件beta
不论你的数据量多大,虚拟树都能毫无压力地处理。
基础用法
基础的树形结构展示
<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) => {
return `${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>
可选择的虚拟树
适用于需要选择层级时使用。
<template>
<el-tree-v2 :data="data" :props="props" show-checkbox :height="208" />
</template>
<script lang="ts" setup>
interface Tree {
id: string
label: string
children?: Tree[]
}
const getKey = (prefix: string, id: number) => {
return `${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>
禁用复选框
节点的复选框可以设置为禁用。
在示例中,属性在 defaultProps 中声明了 disabled
,一些节点被设置为 disable:true
。 相应的复选框已禁用,不能点击。
<template>
<el-tree-v2 :data="data" :props="props" show-checkbox :height="208" />
</template>
<script lang="ts" setup>
interface Tree {
id: string
label: string
children?: Tree[]
}
const getKey = (prefix: string, id: number) => {
return `${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',
disabled: 'disabled',
}
const data = createData(4, 30, 40)
</script>
默认扩展和默认检查
树节点可以在初始化阶段被设置为展开或选中。
分别通过 default-expanded-keys
和 default-checked-keys
设置默认展开和默认选中的节点。
<template>
<el-tree-v2
:data="data"
:height="208"
:props="props"
show-checkbox
:default-checked-keys="defaultCheckedKeys"
:default-expanded-keys="defaultExpandedKeys"
/>
</template>
<script lang="ts" setup>
import { ref } from 'vue'
interface Tree {
id: string
label: string
children?: Tree[]
}
const getKey = (prefix: string, id: number) => {
return `${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)
const checkedKeys: string[] = []
const expanedKeys: string[] = []
for (const datum of data) {
const children = datum.children
if (children) {
expanedKeys.push(datum.id)
checkedKeys.push(children[0].id)
break
}
}
const defaultCheckedKeys = ref(checkedKeys)
const defaultExpandedKeys = ref(expanedKeys)
</script>
自定义节点内容
节点的内容支持自定义,可以在节点区添加按钮或图标等内容
<template>
<el-tree-v2 :data="data" :props="props" :height="208">
<template #default="{ node }">
<span class="prefix" :class="{ 'is-leaf': node.isLeaf }"
>[ElementPlus]</span
>
<span>{{ node.label }}</span>
</template>
</el-tree-v2>
</template>
<script lang="ts" setup>
interface Tree {
id: string
label: string
children?: Tree[]
}
const getKey = (prefix: string, id: number) => {
return `${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>
<style scoped>
.prefix {
color: var(--el-color-primary);
margin-right: 10px;
}
.prefix.is-leaf {
color: var(--el-color-success);
}
</style>
节点过滤
树节点可以过滤
在需要对节点进行过滤时,调用 Tree 实例的 filter
方法, 参数为关键字。 需要注意的是,此时需要设置 filter-method
,值为过滤函数。
<template>
<el-input
v-model="query"
placeholder="Please enter keyword"
@input="onQueryChanged"
/>
<el-tree-v2
ref="treeRef"
:data="data"
:props="props"
:filter-method="filterMethod"
:height="208"
/>
</template>
<script lang="ts" setup>
import { ref } from 'vue'
import { ElTreeV2 } from 'element-plus'
import type { TreeNode } from 'element-plus/es/components/tree-v2/src/types'
interface Tree {
id: string
label: string
children?: Tree[]
}
const getKey = (prefix: string, id: number) => {
return `${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 query = ref('')
const treeRef = ref<InstanceType<typeof ElTreeV2>>()
const data = createData(4, 30, 5)
const props = {
value: 'id',
label: 'label',
children: 'children',
}
const onQueryChanged = (query: string) => {
// TODO: fix typing when refactor tree-v2
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-expect-error
treeRef.value!.filter(query)
}
const filterMethod = (query: string, node: TreeNode) => {
return node.label!.includes(query)
}
</script>
TreeV2 属性
属性 | 说明 | 类型 | 默认值 |
---|---|---|---|
data | 展示数据 | array | — |
empty-text | 内容为空的时候展示的文本 | string | — |
props | 配置选项,具体看下表 | object | — |
highlight-current | 是否高亮当前选中节点 | boolean | false |
expand-on-click-node | 是否在点击节点的时候展开或者收缩节点, 默认值为 true,如果为 false,则只有点箭头图标的时候才会展开或者收缩节点 | boolean | true |
check-on-click-node | 是否在点击节点的时候选中节点,默认值为 false,即只有在点击复选框时才会选中节点 | boolean | false |
default-expanded-keys | 默认展开的节点的 key 的数组 | array | — |
show-checkbox | 节点是否可被选择 | boolean | false |
check-strictly | 在显示复选框的情况下,是否严格的遵循父子不互相关联的做法,默认为 false | boolean | false |
default-checked-keys | 默认勾选的节点的 key 的数组 | array | — |
current-node-key | 当前选中的节点 | string, number | — |
filter-method | 对树节点进行筛选时执行的方法,返回 true 表示这个节点可以显示, 返回 false 则表示这个节点会被隐藏 | Function(value, data) | — |
indent | 相邻级节点间的水平缩进,单位为像素 | number | 16 |
icon | 自定义树节点的图标 | string | Component | - |
props
属性 | 说明 | 类型 | 默认值 |
---|---|---|---|
value | 每个树节点用来作为唯一标识的属性,在整棵树中应该是唯一的 | string, number | id |
label | 指定节点标签为节点对象的某个属性值 | string | label |
children | 指定子树为节点对象的某个属性值 | string | children |
disabled | 指定节点选择框是否禁用为节点对象的某个属性值 | string | disabled |
TreeV2 方法
Tree内部使用TreeNode类型的对象来包装用户传入的数据,用来构造树节点之间的关系。 Tree
暴露了以下方法:
方法 | 说明 | 参数 |
---|---|---|
filter | 对树节点进行筛选操作 | (query: string) |
getCheckedNodes | 若节点可被选择(即show-checkbox 为 true ),则返回目前被选中的节点所组成的数组 | (leafOnly: boolean) |
getCheckedKeys | 若节点可被选择(即 show-checkbox 为 true ),则返回目前被选中的节点的 key 所组成的数组 | (leafOnly: boolean) |
setCheckedKeys | 通过 keys 设置目前勾选的节点 | (keys: TreeKey[]) |
setChecked | 通过 key 设置某个节点的勾选状态 | (key: TreeKey, checked: boolean) |
setExpandedKeys | 设置当前展开的节点 | (keys: TreeKey[]) |
getHalfCheckedNodes | 如果节点可用被选中 (show-checkbox 为 true ), 它将返回当前半选中的节点组成的数组 | - |
getHalfCheckedKeys | 若节点可被选中(show-checkbox 为 true ),则返回目前半选中的节点的 key 所组成的数组 | - |
getCurrentKey | 获取当前被选中节点的 key,若没有节点被选中则返回 undefined | - |
getCurrentNode | 获取当前被选中节点的 data,若没有节点被选中则返回 undefined | - |
setCurrentKey | 通过 key 设置某个节点的当前选中状态 | (key: TreeKey) |
getNode | 通过 key 或 data 获取节点 | (data: TreeKey | TreeNodeData) |
expandNode | 展开指定节点 | (node: TreeNode) |
collapseNode | 折叠指定节点 | (node: TreeNode) |
setData | 当数据量非常庞大的时候,总是使用响应式数据将导致性能表现不佳,所以我们提供一种显式设置的方式来避免此种情况 | (data: TreeData) |
TreeV2 事件
事件名 | 说明 | 参数 |
---|---|---|
node-click | 当节点被点击的时候触发 | (data: TreeNodeData, node: TreeNode, e: MouseEvent) |
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) |
TreeV2 插槽
名称 | 说明 |
---|---|
- | 自定义树节点的内容。 作用域参数为 { node: TreeNode, data: TreeNodeData } |