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

news2025/6/2 9:28:05

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

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

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

<template>
    <!-- 两棵el-tree的节点跨树拖拽实现 -->
    <div class="tree-drag">
        <!-- 左侧树(可拖出) -->
        <el-tree
        :data="treeData1"
        ref="tree1"
        class="tree" 
        node-key="id"
        draggable
        default-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"
        draggable
        default-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.coloradmin.cn/o/2393604.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

从零开始的云计算生活——第十一天,知识延续,程序管理。

一故事背景 今日整体内容是第十天的剩余部分再加上程序管理的开头部分&#xff0c;详细可以回到第十天看新增加内容&#xff0c;现在开始讲解新内容。 二Linux程序与进程 1程序,进程,线程的概念 程序&#xff1a;‌是一段静态的代码&#xff0c;它是应用软件执行的蓝本。程序…

【Dify学习笔记】:Dify离线安装插件教程

Dify离线安装插件教程 1.本地下载插件 插件点击详情页面&#xff0c;安装右边的下载按钮&#xff0c;下载到本地 2.dify插件打包工具 dify-plugin-repackaging 下载后&#xff0c;进入到工具所在目录dify-plugin-repackaging/ git clone https://github.com/junjiem/dif…

基于c++11重构的muduo核心库项目梳理

代码梳理 Thread创建与分配 event_channel回调函数 在muduo中&#xff0c;有三种类型的channel&#xff0c;包括 事件channel(event_channel) 这个就是普通的IO事件channel&#xff0c;当监听到Tcp连接有读、写、关闭、错误事件的时候&#xff0c;event_channel活跃accept_c…

7:OpenCV—图像形态学处理

OpenCV的形态学操作(对象图像进行处理) 包括图像的**腐蚀**、**膨胀**、**开**、**闭**、**形态学梯度、顶帽、黑帽、分支主题、结构元素**等操作。 1.1、膨胀 用33的核去扫描二值图像&#xff0c;当核与图像中的前景像素&#xff08;值为1的像素&#xff09;有**交集**时&…

远控安全金标准,ToDesk、向日葵、网易UU安全功能盘点,是否能攻破防线

目录 一、引言二、设备授权管理2.1、二次验证2.2、访问权限设置2.3、黑/白名单功能 三、远程连接与数据传输3.1、身份认证强度3.2、数据传输加密能力 四、隐私安全功能4.1、隐私屏/黑屏功能对比4.2、风险提醒消息 五、主动防诈保护5.1、24小时防诈等待期5.2、金融类窗口识别与隐…

终端没有5G图标-不支持特定NSA频段组合

某样机没有5G图标&#xff0c;而对比机有5G图标。 step1&#xff1a; 对比机工作在5G NSA上 从android日志可以看到终端工作在b28n78的NSA双载波下 05-06 14:38:51.993097 1582 1661 D RILJ : [UNSL]< UNSOL_PHYSICAL_CHANNEL_CONFIG [ { mConnectionStatusPrimaryS…

第42节:模型优化与部署:Web服务部署(Flask, FastAPI)

1. 引言 在现代人工智能和机器学习应用中,模型的开发只是整个流程的一部分。 将训练好的模型有效地部署为可访问的Web服务,使其能够处理实际请求并返回预测结果,是模型价值实现的关键环节。Python生态系统提供了多种轻量级Web框架,其中Flask和FastAPI是目前最受欢迎的选择…

pikachu通关教程-RCE

目录 RCE(remote command/code execute)概述: exec "ping" 管道符 乱码问题 RCE(remote command/code execute)概述: RCE漏洞&#xff0c;可以让攻击者直接向后台服务器远程注入操作系统命令或者代码&#xff0c;从而控制后台系统 分为远程代码和远程命令两种.当…

MyBatisPlus--快速入门

MyBatisPlus介绍 从名字中就可以感觉到MybatisPlus与MyBatis之间的渊源&#xff0c;而MyBatis是一个非常流行的持久层框架&#xff0c;主要来做数据库的增删改查&#xff0c;而MyBatisPlus这种命名方式让人不得不往MyBatis的升级版去联想&#xff0c;事实也确实如此&#xff0…

鸿蒙 HarmonyOS - SideBarContainer 组件自学指南

在日常开发中&#xff0c;如果你有类似「左侧导航 右侧内容」的布局需求&#xff0c;比如后台管理界面、文件管理器、设置页等&#xff0c;​​SideBarContainer​​ 是非常值得掌握的组件。它自带侧边栏和主内容区的分离机制&#xff0c;还支持折叠、拖拽、控制按钮和多种显示…

C++ list基础概念、list初始化、list赋值操作、list大小操作、list数据插入

list基础概念&#xff1a;list中的每一部分是一个Node&#xff0c;由三部分组成&#xff1a;val、next、prev&#xff08;指向上一个节点的指针&#xff09; list初始化的代码&#xff0c;见下 #include<iostream> #include<list>using namespace std;void printL…

【Linux 学习计划】-- 命令行参数 | 环境变量

目录 命令行参数 环境变量 环境变量的本质是什么&#xff1f; 相关配置文件 修改环境变量的相关操作 代码获取env —— environ 内建命令 结语 命令行参数 试想一下&#xff0c;我们的main函数&#xff0c;也是一个函数&#xff0c;那么我们的main函数有没有参数呢&am…

服务器Docker容器创建与VScode远程连接SSH使用

一、拉取容器 1、win r 输入cmd打开终端命令行 2、终端输入 ping 192.168.xx.xxx 查看是否连接到服务器。如输出显示“字节 时间 TTL”等如下界面&#xff0c;则连接成功。否则输出“请求超时” 如果不能连接&#xff0c;则需要修改设备的IP&#xff0c;需要在设置-网络和In…

LiveQing 视频点播流媒体 RTMP 推流服务功能:搭建 RTMP 视频流媒体服务详细指南

LiveQing视频点播流媒体RTMP推流服务功能&#xff1a;搭建RTMP视频流媒体服务详细指南 一、流媒体服务搭建二、推流工具准备三、创建鉴权直播间四、获取推流地址五、配置OBS推流六、推流及播放七、获取播放地址7.1 页面查看视频源地址7.2 接口查询 八、相关问题解决8.1 大疆无人…

LeetCode 高频 SQL 50 题(基础版)之 【连接】部分 · 下

前五道题&#xff1a;LeetCode 高频 SQL 50 题&#xff08;基础版&#xff09;之 【连接】部分 上 题目&#xff1a;577. 员工奖金 题解&#xff1a; select r.name,b.bonus from Employee r left join Bonus b on r.empIdb.empId where b.bonus <1000 or b.bonus is nul…

【正点原子STM32】RS485串行通信标准(串口基础协议 和 MODBUS协议、总线连接、通信电路、通信波形图、RS485相关HAL库驱动、RS485配置步骤、)

一、RS485介绍 二、RS485相关HAL库驱动介绍 三、RS485配置步骤 四、编程实战 五、总结 串口、 UART、TTL、RS232、RS422、RS485关系 串口、UART、TTL、RS232、RS422和RS485之间的关系可以如此理解&#xff1a; 串口&#xff1a;是一个广义术语&#xff0c;通常指的是采用串行通…

在力扣刷题中触摸算法的温度

在代码的世界里&#xff0c;每一道力扣题目都是一扇通往未知的门。当我推开这些门&#xff0c;与内置求和函数、二进制位运算、辗转相减思想以及链表结构相遇时&#xff0c;才真正触摸到算法的温度 —— 那是一种理性与智慧交织的炽热&#xff0c;也是思维不断淬炼的滚烫。​ 最…

外部访问可视化监控 Grafana (Windows版本)

Grafana 是一款通用&#xff0c;美观的&#xff0c;强大的可视化监控指标的展示工具。可以将不同的数据源数据以图形化的方式展示。它支持多种数据源&#xff0c;如 Prometheus 等&#xff0c;可以满足不同的需求。也可以通过插件和 API 进行扩展满足各种需求&#xff0c;…

通用的防御框架,用于抵御(多模态)大型语言模型的越狱攻击

大家读完觉得有帮助记得关注&#xff01;&#xff01;&#xff01; 摘要 尽管&#xff08;多模态&#xff09;大型语言模型&#xff08;LLMs&#xff09;因其卓越的能力而受到广泛关注&#xff0c;但它们仍然容易受到越狱攻击。已经提出了各种防御方法来防御越狱攻击&#xff…

新能源汽车电控系统的精准守护者PKDV5355高压差分探头

在新能源汽车的"心脏"——电控系统中&#xff0c;每一次电流的精准切换都关乎车辆的性能与安全。PRBTEK PKDV5355高压差分探头就像一位经验丰富的"汽车医生"&#xff0c;帮助工程师们精准捕捉IGBT模块的每一次"心跳"&#xff0c;确保电驱系统健康…