Vue3 vxeTree树形组件完全指南:从入门到精通的完整使用教程

发布于:2025-08-15 ⋅ 阅读:(19) ⋅ 点赞:(0)

简介

虽然 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-input
      v-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-tree
      ref="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 是一个功能强大、配置灵活的树形组件,主要特点包括:

  1. 丰富的配置选项:支持自定义数据格式、显示样式、交互行为等
  2. 强大的交互功能:支持拖拽排序、搜索过滤、多选等
  3. 异步加载支持:可以轻松实现懒加载功能
  4. 完善的事件系统:提供丰富的事件回调
  5. 良好的扩展性:支持自定义渲染和样式

vxe-tree 官方文档

 Vue3 vxeTree树形组件完全指南:从入门到精通的完整使用教程 - 高质量源码分享平台-免费下载各类网站源码与模板及前沿技术分享


网站公告

今日签到

点亮在社区的每一天
去签到