当前位置:首页 > 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. 双向数据绑定:维护源树和目标树两个数据源,通过操作这两个数组实现节点移动。

    vue实现树穿梭

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

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

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

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

    vue实现树穿梭

注意事项

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

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

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

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

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

标签: vue
分享给朋友:

相关文章

vue项目实现

vue项目实现

Vue 项目实现指南 环境准备 确保已安装 Node.js(建议版本 14+)和 npm/yarn。通过以下命令检查版本: node -v npm -v 安装 Vue CLI(脚手架工具): np…

vue实现活动倒计时

vue实现活动倒计时

实现活动倒计时的基本思路 在Vue中实现活动倒计时通常需要获取当前时间与活动结束时间的差值,并将其转换为天、小时、分钟、秒的格式展示。通过定时器每秒更新显示的时间。 定义倒计时数据 在Vue组件的d…

vue实现主页

vue实现主页

Vue 实现主页的基本步骤 创建一个 Vue 主页通常涉及以下几个关键步骤,从项目初始化到页面布局和功能实现。 初始化 Vue 项目 使用 Vue CLI 或 Vite 初始化项目。Vue CLI…

vue实现文字

vue实现文字

Vue 中实现文字显示的方法 在 Vue 中实现文字显示可以通过多种方式,包括插值表达式、指令、组件等。以下是几种常见的实现方法: 插值表达式 使用双大括号 {{ }} 进行文本插值,这是 Vue…

vue 实现拖拉

vue 实现拖拉

Vue 实现拖拽功能的方法 使用 HTML5 原生拖放 API HTML5 提供了原生的拖放 API,可以通过 draggable 属性、dragstart、dragend、dragover 和 dr…

vue mvvm 实现

vue mvvm 实现

Vue MVVM 实现原理 Vue.js 的 MVVM(Model-View-ViewModel)架构通过数据绑定和响应式系统实现视图与数据的自动同步。以下是其核心实现机制: 数据劫持与响应式系统…