当前位置:首页 > VUE

vue实现树穿梭

2026-01-11 23:34:49VUE

Vue 实现树穿梭功能

树穿梭功能通常用于在两个树形结构之间移动节点,常见于权限管理、数据分类等场景。以下是基于 Vue 的实现方法:

使用 Element UI 的 Tree 组件

Element UI 提供了成熟的 Tree 和 Transfer 组件,可以组合实现树穿梭功能。

安装 Element UI:

npm install element-ui

示例代码:

<template>
  <div>
    <el-transfer
      v-model="selectedNodes"
      :data="treeData"
      :props="treeProps"
      :left-default-checked="leftChecked"
      :right-default-checked="rightChecked"
      filterable
      :titles="['源树', '目标树']"
    >
      <el-tree
        slot="left"
        ref="leftTree"
        :data="leftTreeData"
        :props="treeProps"
        show-checkbox
        node-key="id"
        @check-change="handleLeftCheckChange"
      ></el-tree>
      <el-tree
        slot="right"
        ref="rightTree"
        :data="rightTreeData"
        :props="treeProps"
        show-checkbox
        node-key="id"
        @check-change="handleRightCheckChange"
      ></el-tree>
    </el-transfer>
  </div>
</template>

<script>
export default {
  data() {
    return {
      leftTreeData: [
        { id: 1, label: '一级 1', children: [{ id: 4, label: '二级 1-1' }] },
        { id: 2, label: '一级 2', children: [{ id: 5, label: '二级 2-1' }] },
        { id: 3, label: '一级 3', children: [{ id: 6, label: '二级 3-1' }] }
      ],
      rightTreeData: [],
      selectedNodes: [],
      treeProps: {
        label: 'label',
        children: 'children'
      },
      leftChecked: [],
      rightChecked: []
    }
  },
  methods: {
    handleLeftCheckChange(node, checked) {
      if (checked) {
        this.leftChecked = [...this.leftChecked, node.id]
      } else {
        this.leftChecked = this.leftChecked.filter(id => id !== node.id)
      }
    },
    handleRightCheckChange(node, checked) {
      if (checked) {
        this.rightChecked = [...this.rightChecked, node.id]
      } else {
        this.rightChecked = this.rightChecked.filter(id => id !== node.id)
      }
    }
  },
  computed: {
    treeData() {
      return [...this.leftTreeData, ...this.rightTreeData]
    }
  }
}
</script>

自定义实现树穿梭

如果需要更自定义的功能,可以完全自己实现:

<template>
  <div class="tree-transfer">
    <div class="tree-container">
      <h3>源树</h3>
      <tree
        :data="sourceTree"
        :props="treeProps"
        show-checkbox
        node-key="id"
        ref="sourceTree"
        @check-change="handleSourceCheckChange"
      ></tree>
    </div>
    <div class="transfer-buttons">
      <button @click="moveToTarget">→</button>
      <button @click="moveToSource">←</button>
    </div>
    <div class="tree-container">
      <h3>目标树</h3>
      <tree
        :data="targetTree"
        :props="treeProps"
        show-checkbox
        node-key="id"
        ref="targetTree"
        @check-change="handleTargetCheckChange"
      ></tree>
    </div>
  </div>
</template>

<script>
export default {
  data() {
    return {
      sourceTree: [
        { id: 1, label: '节点1', children: [{ id: 2, label: '子节点1' }] },
        { id: 3, label: '节点2' }
      ],
      targetTree: [],
      treeProps: {
        label: 'label',
        children: 'children'
      },
      checkedSourceNodes: [],
      checkedTargetNodes: []
    }
  },
  methods: {
    handleSourceCheckChange(node, checked) {
      if (checked) {
        this.checkedSourceNodes.push(node.id)
      } else {
        this.checkedSourceNodes = this.checkedSourceNodes.filter(id => id !== node.id)
      }
    },
    handleTargetCheckChange(node, checked) {
      if (checked) {
        this.checkedTargetNodes.push(node.id)
      } else {
        this.checkedTargetNodes = this.checkedTargetNodes.filter(id => id !== node.id)
      }
    },
    moveToTarget() {
      const nodesToMove = this.$refs.sourceTree.getCheckedNodes()
      this.targetTree = [...this.targetTree, ...nodesToMove]
      this.sourceTree = this.removeNodes(this.sourceTree, this.checkedSourceNodes)
      this.checkedSourceNodes = []
    },
    moveToSource() {
      const nodesToMove = this.$refs.targetTree.getCheckedNodes()
      this.sourceTree = [...this.sourceTree, ...nodesToMove]
      this.targetTree = this.removeNodes(this.targetTree, this.checkedTargetNodes)
      this.checkedTargetNodes = []
    },
    removeNodes(tree, ids) {
      return tree.filter(node => {
        if (ids.includes(node.id)) return false
        if (node.children) {
          node.children = this.removeNodes(node.children, ids)
        }
        return true
      })
    }
  }
}
</script>

<style>
.tree-transfer {
  display: flex;
  justify-content: space-between;
}
.tree-container {
  width: 45%;
}
.transfer-buttons {
  display: flex;
  flex-direction: column;
  justify-content: center;
}
</style>

关键实现要点

  1. 双向数据绑定:维护源树和目标树两个数据源,通过操作这两个数组实现节点移动。

  2. 节点选择:利用 Tree 组件的复选框功能,记录选中的节点。

  3. 节点移动:将选中节点从源树移到目标树,或反向移动。

  4. 树形结构处理:递归处理子节点,确保移动时保持树形结构完整。

  5. 性能优化:对于大型树结构,考虑使用虚拟滚动或懒加载技术。

注意事项

  1. 节点标识:确保每个节点有唯一标识符(如id),便于操作和查找。

  2. 状态同步:移动节点后及时清空已选节点列表。

  3. 深度复制:移动节点时进行深拷贝,避免引用问题。

  4. 自定义样式:根据需求调整穿梭框和按钮的样式布局。

    vue实现树穿梭

以上两种方法都可以实现树穿梭功能,Element UI 方案更快捷,自定义方案更灵活。可以根据项目需求选择适合的实现方式。

标签: vue
分享给朋友:

相关文章

实现vue

实现vue

安装Vue.js 通过npm安装Vue.js是最常见的方式。确保已安装Node.js和npm,运行以下命令: npm install vue 或者使用CDN直接引入: <script src…

vue实现模块

vue实现模块

Vue 实现模块化的方法 Vue 支持多种模块化开发方式,可以根据项目需求选择适合的方案。 使用单文件组件(SFC) 单文件组件是 Vue 最常用的模块化方式,将模板、脚本和样式封装在一个 .vue…

vue 实现筛选

vue 实现筛选

实现筛选功能的基本方法 在Vue中实现筛选功能通常涉及以下几个核心步骤: 数据绑定与筛选逻辑 使用v-model绑定筛选条件到Vue实例的数据属性,结合计算属性实现动态筛选: data() {…

vue下载实现

vue下载实现

Vue 下载实现方法 在 Vue 项目中实现文件下载功能可以通过多种方式完成,以下是几种常见的方法: 使用 <a> 标签实现下载 通过动态创建 <a> 标签并设置 href…

vue 实现原理

vue 实现原理

Vue 实现原理 Vue.js 是一个渐进式 JavaScript 框架,其核心实现原理主要包括响应式系统、虚拟 DOM、模板编译和组件化机制。以下是 Vue 实现原理的核心要点: 响应式系统 Vu…

vue如何实现排序

vue如何实现排序

实现数组排序 在Vue中实现数组排序可以通过computed属性或methods来处理。假设有一个数组items,可以创建一个计算属性返回排序后的数组: data() { return {…