当前位置: 首页 > article >正文

vue2使用el-tree实现两棵树间节点的拖拽复制

原文链接:两棵el-tree的节点跨树拖拽实现

参照这篇文章,把它做成组件,新增左侧树(可拖出)被拖节点变灰提示;

拖拽中
在这里插入图片描述
拖拽后
在这里插入图片描述
TreeDragComponent.vue

<template><!-- 两棵el-tree的节点跨树拖拽实现 --><div class="tree-drag"><!-- 左侧树(可拖出) --><el-tree:data="treeData1"ref="tree1"class="tree" node-key="id"draggabledefault-expand-all:allow-drop="returnFalse":props="defaultProps"@node-drag-start="handleDragstart"@node-drag-end="handleDragend"><!-- 使用作用域插槽自定义节点样式 --><span slot-scope="{ node, data }" :class="{ 'custom-red': data.isHighlighted }">{{ node.label }}</span></el-tree><!-- 右侧树(可拖入) --><el-tree:data="treeData2" ref="tree2"class="tree" node-key="id"draggabledefault-expand-all:props="defaultProps":allow-drop="returnTrue"></el-tree></div>
</template><script>
export default {
name: "TreeDrag",
props:['treeData1','treeData2'],
data() {return {defaultProps: {children: 'children',label: 'name'},};
},
methods: {// (1) 手动触发:该节点向父组件通知拖拽开始(只不过目标树是右侧树)// 经过这个移花接木的操作,右侧的树会误以为是自身的节点触发了tree-node-drag-start事件,它会将被拖拽节点保存在组件内handleDragstart (node, event) {this.$refs.tree2.$emit('tree-node-drag-start', event, {node: node});},// (2) 鼠标滑过阶段// 当鼠标拖拽着左侧树上的节点从右侧树上的节点划过(也就是触发dragover事件)时,右侧树会误以为是在拖拽自己的节点,因此会在tree-node-drag-over事件中自动执行位置计算,所以这一阶段无需我们干预。// (3)鼠标释放阶段// 尽管此时右侧树已经误以为被拖拽的是自身节点,但被拖拽的节点此时仍然是左侧树的子组件,所以当鼠标释放时,它只能向左侧树(即它的父组件)触发tree-node-drag-end事件。由于左侧树不允许释放,所以此时节点并没有发生移动。// 为了让右侧树收到鼠标释放的通知,我们开始进行第二次移花接木,即把左侧树上发生的tree-node-drag-end事件以同样的方式触发给右侧树handleDragend (draggingNode, endNode, position, event) {//不只是做节点移动,而是拖拽复制,也就是要保留左侧树上的原节点//真正要保留原节点很难实现,所以选择在移动后恢复左侧树上的节点// 插入一个空节点用于占位let emptyData = {id: (+new Date), children: []};this.$refs.tree1.insertBefore(emptyData, draggingNode);this.$refs.tree2.$emit('tree-node-drag-end', event);this.$nextTick(() => {// 如果是移动到了当前树上,需要清掉空节点if (this.$refs.tree1.getNode(draggingNode.data)) {this.$refs.tree1.remove(emptyData);} else {// 如果移动到了别的树上,需要恢复该节点,并清掉空节点let data = JSON.parse(JSON.stringify(draggingNode.data));this.createHighlightedNode(data); // 添加标记字段this.$refs.tree1.insertAfter(data, this.$refs.tree1.getNode(emptyData));this.$refs.tree1.remove(emptyData);}})},// 递归创建带高亮标记的节点createHighlightedNode(data) {// 给当前节点添加 isHighlighted 属性data.isHighlighted = true;// 检查是否有子节点if (data.children && Array.isArray(data.children)) {// 递归处理每个子节点data.children.forEach(child => {this.createHighlightedNode(child);});}return data;},// 允许内部拖拽returnTrue () {// 可传参数:draggingNode, dropNode, type// 校验所有拖拽节点是否允许放入(如只能放入同级或特定父级)// return this.draggingNodes.every(node => //     node.level <= 2 &&  // 限制最大层级//     node.type !== 'system'  // 限制类型// )return true;},// 禁止内部拖拽returnFalse () {return false;}
}
};
</script><style lang="scss" scoped>
.tree-drag {display: flex;justify-content: space-between;.tree {flex-grow: 1;.custom-red {color: #E4E4E4 !important; /* 红色背景 */font-size: 14px !important;}}}
</style>

Parent.vue

<TreeDrag :treeData1="treeDataLeft" :treeData2="treeDataRight"></TreeDrag>

element-ui源码中用于定义树节点的element-ui\packages\tree\src\tree-node.vue组件
在这里插入图片描述

下一篇:在此基础上加功能,el-tree拖拽事件,限制同级拖拽,获取拖拽后节点的前后节点,同级拖拽合并父节点name且子节点加入目标节点里

http://www.lryc.cn/news/2393604.html

相关文章:

  • 前端开发中 <> 符号解析问题全解:React、Vue 与 UniApp 场景分析与解决方案
  • 封装一个Qt调用动态库的类
  • [python] 最大公约数 和 最小公倍数
  • 如何在 Django 中集成 MCP Server
  • 从零开始的云计算生活——第十一天,知识延续,程序管理。
  • React 事件处理与合成事件机制揭秘
  • 【React】jsx 从声明式语法变成命令式语法
  • 【Dify学习笔记】:Dify离线安装插件教程
  • 基于c++11重构的muduo核心库项目梳理
  • GitHub 趋势日报 (2025年05月29日)
  • Oracle 19c导入数据出现ORA-56935 ORA-39065
  • Java大师成长计划之第35天:未来展望与个人总结
  • 7:OpenCV—图像形态学处理
  • 远控安全金标准,ToDesk、向日葵、网易UU安全功能盘点,是否能攻破防线
  • 终端没有5G图标-不支持特定NSA频段组合
  • Netty 实战篇:为 Netty RPC 框架引入调用链追踪,实现链路透明化
  • 第42节:模型优化与部署:Web服务部署(Flask, FastAPI)
  • pikachu通关教程-RCE
  • MyBatisPlus--快速入门
  • 鸿蒙 HarmonyOS - SideBarContainer 组件自学指南
  • 数据交易场景的数据质量评估
  • C++ list基础概念、list初始化、list赋值操作、list大小操作、list数据插入
  • 39. 自动化异步测试开发之编写异步业务函数、测试函数和测试类(函数写法)
  • Go语言defer关键字:延迟执行的精妙设计
  • 提升WSL中Ubuntu编译速度的完整指南
  • 【Linux 学习计划】-- 命令行参数 | 环境变量
  • 服务器Docker容器创建与VScode远程连接SSH使用
  • 体现物联网环境下安全防护的紧迫性 :物联网环境下的个人信息安全:隐忧与防护之道
  • LiveQing 视频点播流媒体 RTMP 推流服务功能:搭建 RTMP 视频流媒体服务详细指南
  • LeetCode 高频 SQL 50 题(基础版)之 【连接】部分 · 下