7.5el-tree 组件详解
el-tree
el-tree
是 Element Plus 提供的树形控件,用于展示具有层级关系的数据,如组织架构、文件目录、分类菜单等。
一、基本用法
<template><el-tree :data="treeData" :props="defaultProps" @node-click="handleNodeClick" />
</template><script setup>
import { ref } from 'vue'// 树形数据
const treeData = ref([{label: '一级 1',children: [{label: '二级 1-1',children: [{ label: '三级 1-1-1' },{ label: '三级 1-1-2' }]}]},{label: '一级 2',children: [{ label: '二级 2-1' },{ label: '二级 2-2' }]}
])// 节点渲染配置
const defaultProps = {children: 'children',label: 'label'
}const handleNodeClick = (data, node, component) => {console.log('节点被点击:', data)
}
</script>
✅ 说明:
data
:树的数据源,数组格式。props
:配置节点的label
和children
字段名。- 默认情况下,节点可展开/折叠。
二、核心属性(Props)
属性 | 类型 | 说明 | 默认值 |
---|---|---|---|
data | array | 树的数据源 | [] |
props | object | 配置节点的 label 、children 、disabled 等字段 | { label: 'label', children: 'children' } |
node-key | string | 每个节点的唯一标识字段名(用于勾选、展开等状态持久化) | - |
default-expand-all | boolean | 是否默认展开所有节点 | false |
expand-on-click-node | boolean | 是否在点击节点时展开/折叠节点 | true |
check-on-click-node | boolean | 是否在点击节点时选中节点 | false |
default-expanded-keys | string[] | 默认展开的节点 key 数组 | [] |
auto-expand-parent | boolean | 展开子节点时是否自动展开父节点 | true |
show-checkbox | boolean | 节点是否可被选择(显示复选框) | false |
check-strictly | boolean | 是否严格遵循父子不互相关联 | false |
default-checked-keys | string[] | 默认勾选的节点 key 数组 | [] |
highlight-current | boolean | 是否高亮当前选中节点 | false |
draggable | boolean | 是否开启拖拽节点 | false |
allow-drag | Function | 判断节点能否被拖拽 | - |
allow-drop | Function | 拖拽时判定目标节点能否被放置 | - |
三、重要事件(Events)
事件名 | 说明 | 回调参数 |
---|---|---|
node-click | 节点被点击时触发 | (data, node, component) |
node-contextmenu | 右键节点时触发 | (event, data, node, component) |
check-change | 节点选中状态变化时触发 | (data, checked, indeterminate) |
check | 勾选节点时触发(父子联动) | (data, checkedStatus) |
current-change | 当前选中节点变化时触发 | (data, node) |
node-expand | 节点被展开时触发 | (data, node, component) |
node-collapse | 节点被折叠时触发 | (data, node, component) |
node-drag-start | 拖拽开始时触发 | (node, event) |
node-drag-end | 拖拽结束时触发 | (node, endDropNode, dropType, event) |
node-drop | 拖拽放置时触发 | (node, dragNode, dropType, event) |
四、常用方法(通过 ref 调用)
const treeRef = ref(null)// 获取当前选中节点
treeRef.value.getCurrentKey()// 设置当前选中节点
treeRef.value.setCurrentKey(key)// 获取当前选中节点数据
treeRef.value.getCurrentNode()// 获取被勾选节点(show-checkbox 时)
treeRef.value.getCheckedKeys() // 返回 key 数组
treeRef.value.getCheckedNodes() // 返回节点数据数组// 设置节点勾选
treeRef.value.setCheckedKeys([key1, key2])// 获取半选中节点(父子不联动时)
treeRef.value.getHalfCheckedKeys()
treeRef.value.getHalfCheckedNodes()// 手动展开/折叠节点
treeRef.value.getNode(key).expanded = true
五、高级功能
1. 带复选框的树(可多选)
<el-tree:data="treeData"show-checkboxnode-key="id":default-checked-keys="[2]"@check-change="handleCheckChange"
/>
const handleCheckChange = (data, checked, indeterminate) => {console.log(`${data.label} 选中状态: ${checked}, 半选: ${indeterminate}`)
}
🔍
check-strictly
:设为true
时,父子节点选中状态不互相关联。
2. 异步加载树节点
适用于大数据量或按需加载场景。
<el-tree:data="treeData"node-key="id":props="asyncProps":load="loadNode"lazy
/>
const asyncProps = {children: 'children',label: 'label',isLeaf: 'leaf' // 标记是否为叶子节点
}const loadNode = (node, resolve) => {if (node.level === 0) {return resolve([{ label: '根目录', id: 1 }])}if (node.level > 3) return resolve([])// 模拟异步请求setTimeout(() => {const data = Array.from({ length: 3 }, (_, i) => ({label: `子节点 ${node.data.label}-${i + 1}`,id: Math.random(),leaf: node.level >= 2 // 2层以下为叶子}))resolve(data)}, 500)
}
3. 自定义节点内容
使用 #default
插槽自定义节点渲染。
<el-tree :data="treeData" :props="defaultProps"><template #default="{ node, data }"><span class="custom-tree-node"><span>{{ node.label }}</span><span><el-button size="small" @click="() => append(data)">新增</el-button><el-button size="small" type="danger" @click="() => remove(node, data)">删除</el-button></span></span></template>
</el-tree>
4. 拖拽排序
<el-tree:data="treeData"node-key="id"draggable:allow-drop="allowDrop":allow-drag="allowDrag"@node-drop="handleDrop"
/>
const allowDrop = (draggingNode, dropNode, type) => {// 不允许将父节点拖拽到子节点下if (type === 'inner' && draggingNode.data.children) {return false}return true
}const allowDrag = (draggingNode) => {return draggingNode.data.label.indexOf('不可拖拽') === -1
}const handleDrop = (dragNode, dropNode, dropType, ev) => {ElMessage.success(`拖拽成功: ${dropType}`)
}
六、 完整案例
<script setup>
import { ref, onMounted } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'// 树引用
const treeRef = ref(null)// 树数据
const treeData = ref([{id: 1,label: '部门A',children: [{ id: 2, label: '小组A1' },{ id: 3, label: '小组A2' }]},{id: 4,label: '部门B',children: [{ id: 5, label: '小组B1' }]}
])// 配置
const defaultProps = {children: 'children',label: 'label'
}// 事件
const handleNodeClick = (data) => {ElMessage.info(`点击了: ${data.label}`)
}const handleCheckChange = (data, checked) => {console.log(`${data.label} 勾选状态: ${checked}`)
}const getCheckedKeys = () => {const keys = treeRef.value.getCheckedKeys()ElMessage.info('已勾选: ' + keys.join(', '))
}const append = (data) => {const newChild = { id: Date.now(), label: '新节点' }if (!data.children) data.children = []data.children.push(newChild)
}const remove = (node, data) => {const parent = node.parentconst children = parent.data.children || parent.dataconst index = children.findIndex(d => d.id === data.id)children.splice(index, 1)
}onMounted(() => {// 可在此处加载异步数据
})
</script><template><div class="p-4"><h3 class="mb-4">组织架构树</h3><el-button size="small" @click="getCheckedKeys" class="mb-4">获取勾选节点</el-button><el-treeref="treeRef":data="treeData":props="defaultProps"node-key="id"show-checkboxdefault-expand-allhighlight-current@node-click="handleNode-click"@check-change="handleCheckChange"><template #default="{ node, data }"><span class="flex items-center"><span>{{ node.label }}</span><span class="ml-2"><el-button type="primary" link size="small" @click="append(data)">新增</el-button><el-button type="danger" link size="small" @click="remove(node, data)">删除</el-button></span></span></template></el-tree></div>
</template><style scoped>
.custom-tree-node {flex: 1;display: flex;align-items: center;justify-content: space-between;font-size: 14px;padding-right: 8px;
}
</style>
✅ 最佳实践建议
- 必须设置
node-key
:用于状态持久化,否则勾选/展开状态会错乱。 - 大数据量使用
lazy
懒加载:避免一次性渲染卡顿。 - 合理使用
check-strictly
:根据业务决定父子是否联动。 - 拖拽功能谨慎使用:需配合后端保存新顺序。