Vue3 vxeTree树形组件完全指南:从入门到精通的完整使用教程
简介
虽然 element-plus 和 ant-design 等 UI 库中都提供了 tree 组件,但是当前开源组件库中,无法将所有方法和属性集中到单一的树形组件中,所以我希望写一个功能齐全的业务通用组件。
安装与引入
安装依赖
# NPM
$ npm install vxe-tree --save# Yarn
$ yarn add vxe-tree# pnpm
$ pnpm install vxe-tree
引入组件
import Vue from "vue";
import vxeTree from "vxe-tree";
import "vxe-tree/dist/index.css";Vue.use(vxeTree);
基础用法
最简单的树形结构
<template><div><vxe-tree :data="treeData" :config="treeConfig" /></div>
</template><script>
export default {data() {return {treeData: [{id: "1",label: "根节点1",children: [{id: "1-1",label: "子节点1-1",children: [{ id: "1-1-1", label: "子节点1-1-1" },{ id: "1-1-2", label: "子节点1-1-2" },],},{ id: "1-2", label: "子节点1-2" },],},{id: "2",label: "根节点2",children: [{ id: "2-1", label: "子节点2-1" },{ id: "2-2", label: "子节点2-2" },],},],treeConfig: {children: "children",hasChild: "hasChild",id: "id",label: "label",},};},
};
</script>
数据格式
标准数据格式
const treeData = [{id: "1", // 节点唯一标识label: "节点名称", // 显示文本children: [], // 子节点数组hasChild: false, // 是否有子节点(用于异步加载)disabled: false, // 是否禁用checked: false, // 是否选中expanded: false, // 是否展开loading: false, // 是否加载中icon: "icon-class", // 自定义图标},
];
自定义数据格式
const customTreeData = [{nodeId: "1",nodeName: "自定义节点",childNodes: [],hasChildren: true,isDisabled: false,isSelected: false,isExpanded: false,},
];const customConfig = {children: "childNodes",hasChild: "hasChildren",id: "nodeId",label: "nodeName",disabled: "isDisabled",checked: "isSelected",expanded: "isExpanded",
};
配置选项
基础配置
const treeConfig = {// 数据字段映射children: "children", // 子节点字段名hasChild: "hasChild", // 是否有子节点字段名id: "id", // 节点ID字段名label: "label", // 显示文本字段名disabled: "disabled", // 禁用状态字段名checked: "checked", // 选中状态字段名expanded: "expanded", // 展开状态字段名loading: "loading", // 加载状态字段名icon: "icon", // 图标字段名// 显示配置showLine: true, // 是否显示连接线showIcon: true, // 是否显示图标showCheckbox: false, // 是否显示复选框showRadio: false, // 是否显示单选框showExpand: true, // 是否显示展开按钮// 交互配置accordion: false, // 是否手风琴模式checkStrictly: false, // 是否严格模式(父子节点不关联)checkOnClickNode: false, // 点击节点时是否选中expandOnClickNode: false, // 点击节点时是否展开// 样式配置nodeKey: "id", // 节点唯一标识字段defaultExpandAll: false, // 是否默认展开所有节点defaultExpandedKeys: [], // 默认展开的节点defaultCheckedKeys: [], // 默认选中的节点highlightCurrent: true, // 是否高亮当前选中节点
};
高级配置
const advancedConfig = {// 异步加载配置lazy: false, // 是否启用异步加载load: null, // 异步加载函数// 拖拽配置draggable: false, // 是否启用拖拽allowDrop: null, // 拖拽放置判断函数allowDrag: null, // 拖拽开始判断函数// 搜索配置filterNodeMethod: null, // 节点过滤方法// 渲染配置renderContent: null, // 自定义节点内容渲染renderIcon: null, // 自定义图标渲染// 事件配置onNodeClick: null, // 节点点击事件onNodeExpand: null, // 节点展开事件onNodeCollapse: null, // 节点收起事件onCheckChange: null, // 选中状态变化事件
};
事件处理
基础事件
<template><vxe-tree:data="treeData":config="treeConfig"@node-click="handleNodeClick"@node-expand="handleNodeExpand"@node-collapse="handleNodeCollapse"@check-change="handleCheckChange"/>
</template><script>
export default {methods: {// 节点点击事件handleNodeClick(data, node, event) {console.log("点击节点:", data);console.log("节点信息:", node);console.log("事件对象:", event);},// 节点展开事件handleNodeExpand(data, node) {console.log("展开节点:", data);// 可以在这里进行异步加载this.loadChildNodes(data, node);},// 节点收起事件handleNodeCollapse(data, node) {console.log("收起节点:", data);},// 选中状态变化事件handleCheckChange(data, checked, indeterminate) {console.log("选中状态变化:", data, checked, indeterminate);},},
};
</script>
异步加载示例
// 异步加载子节点
async loadChildNodes(data, node) {try {// 设置加载状态this.$set(data, 'loading', true)// 模拟API请求const response = await this.fetchChildNodes(data.id)// 更新子节点数据this.$set(data, 'children', response.data)this.$set(data, 'hasChild', false)} catch (error) {console.error('加载子节点失败:', error)} finally {this.$set(data, 'loading', false)}
},// 模拟API请求
async fetchChildNodes(parentId) {return new Promise((resolve) => {setTimeout(() => {resolve({data: [{ id: `${parentId}-1`, label: `子节点${parentId}-1` },{ id: `${parentId}-2`, label: `子节点${parentId}-2` }]})}, 1000)})
}
高级功能
搜索过滤
<template><div><vxe-inputv-model="searchKeyword"placeholder="搜索节点"@input="handleSearch"/><vxe-tree ref="tree" :data="filteredTreeData" :config="treeConfig" /></div>
</template><script>
export default {data() {return {searchKeyword: "",originalTreeData: [], // 原始数据filteredTreeData: [], // 过滤后的数据treeConfig: {filterNodeMethod: this.filterNode,},};},methods: {// 节点过滤方法filterNode(value, data, node) {if (!value) return true;return data.label.toLowerCase().includes(value.toLowerCase());},// 搜索处理handleSearch() {this.filteredTreeData = this.filterTreeData(this.originalTreeData,this.searchKeyword);},// 递归过滤树数据filterTreeData(data, keyword) {return data.filter((item) => {const match = item.label.toLowerCase().includes(keyword.toLowerCase());if (item.children && item.children.length > 0) {item.children = this.filterTreeData(item.children, keyword);return match || item.children.length > 0;}return match;});},},
};
</script>
拖拽排序
<template><vxe-tree :data="treeData" :config="treeConfig" @node-drop="handleNodeDrop" />
</template><script>
export default {data() {return {treeConfig: {draggable: true,allowDrop: this.allowDrop,allowDrag: this.allowDrag,},};},methods: {// 允许拖拽判断allowDrag(node) {// 不允许拖拽根节点return node.level !== 0;},// 允许放置判断allowDrop(draggingNode, dropNode, type) {// 不允许放置到禁用节点if (dropNode.data.disabled) return false;// 不允许放置到自己或自己的子节点if (draggingNode.data.id === dropNode.data.id) return false;return true;},// 拖拽完成事件handleNodeDrop(draggingNode, dropNode, dropType, ev) {console.log("拖拽完成:", {draggingNode: draggingNode.data,dropNode: dropNode.data,dropType, // 'prev', 'inner', 'next'event: ev,});// 这里可以调用API更新数据this.updateNodePosition(draggingNode.data.id, dropNode.data.id, dropType);},},
};
</script>
多选功能
<template><div><vxe-treeref="tree":data="treeData":config="treeConfig"@check-change="handleCheckChange"/><div class="actions"><vxe-button @click="getCheckedNodes">获取选中节点</vxe-button><vxe-button @click="setCheckedNodes">设置选中节点</vxe-button><vxe-button @click="clearChecked">清空选中</vxe-button></div></div>
</template><script>
export default {data() {return {treeConfig: {showCheckbox: true,checkStrictly: false, // 父子节点关联defaultCheckedKeys: ["1-1"], // 默认选中节点},};},methods: {// 获取选中的节点getCheckedNodes() {const checkedNodes = this.$refs.tree.getCheckedNodes();console.log("选中的节点:", checkedNodes);},// 设置选中节点setCheckedNodes() {this.$refs.tree.setCheckedKeys(["1-1", "1-2"]);},// 清空选中clearChecked() {this.$refs.tree.setCheckedKeys([]);},// 选中状态变化handleCheckChange(data, checked, indeterminate) {console.log("选中状态变化:", {node: data,checked,indeterminate,});},},
};
</script>
总结
vxeTree 是一个功能强大、配置灵活的树形组件,主要特点包括:
- 丰富的配置选项:支持自定义数据格式、显示样式、交互行为等
- 强大的交互功能:支持拖拽排序、搜索过滤、多选等
- 异步加载支持:可以轻松实现懒加载功能
- 完善的事件系统:提供丰富的事件回调
- 良好的扩展性:支持自定义渲染和样式
vxe-tree 官方文档
Vue3 vxeTree树形组件完全指南:从入门到精通的完整使用教程 - 高质量源码分享平台-免费下载各类网站源码与模板及前沿技术分享