【vue】使用drag实现文件夹拖动效果

需求:仿照windows系统的文件管理样式,在网页中实现文件夹及文件管理的效果,可以对文件拖动进行合并、上传等功能

一、实现的效果图

在这里插入图片描述
在这里插入图片描述

二、技术路线

1、使用js实现

刚接到需求的时候,考虑使用onmouseMove监听鼠标当前的坐标位置,并将其应用到拖动的元素中,大概的写法如下:

window.onload = function () {
            var box = document.getElementById("box");
            document.onmousemove = function (event) {
                var left = event.clientX;
                var top = event.clientY;
                box.style.left = left + "px";
                box.style.top = top + "px";
            }
        };

但是实现的效果并不好,能够感受到非常明显的延迟,拖动起来有卡顿感,故结合需求更换技术路线为@drag

2、使用@drag实现

//用户开始拖动元素时触发
@dragstart="dragstart"
//元素正在拖动时触发
@drag="drag"
// 用户完成元素拖动后触发
@dragend="dragend"
//将元素设置为可被拖动的
:draggable="true"

//当被鼠标拖动的对象进入其容器范围内时触发此事件,event.target为当前dom元素
@dragenter="dragenter($event)"
//当某被拖动的对象在另一对象容器范围内拖动时触发此事件,主要是设置拖拽时不为禁止🚫标志
@dragover="dragover($event)"
//当被鼠标拖动的对象离开其容器范围内时触发此事件
@dragleave="dragleave($event)"
//在一个拖动过程中,释放鼠标键时触发此事件
@drop="drop($event)"

总结下来就是,对于想要 实现拖动效果的元素 使用前四个事件,对于 被其他元素拖入其内部的元素 使用后四个事件。

对应我们的需求,文件和文件夹就是想要实现拖动效果的元素文件夹和磁盘是被其他元素拖入其内部的元素

@drag的使用的体验非常丝滑,故而选择该技术路线。

三、拖拽功能的实现

关于拖拽部分有两点需要实现,一是拖拽的逻辑部分,二是拖拽时的样式显示部分。我们先说逻辑部分,处理拖拽的根本逻辑就是要知道当前拖拽的是哪个元素和释放在哪个元素中。下面详细说明一下各事件如何使用:

//对文件元素和文件夹元素使用该事件
@dragstart="dragstart('文件或文件夹名字','磁盘名')"
//用来记录当前拖动的元素的信息
dragstart(item,type){
	console.log("当前拖拽的元素为:",item,"所在的磁盘为:",type);
}
//对文件夹元素使用该事件
@drop="drop('文件夹名字',$event,'磁盘名')"
//对磁盘元素使用该事件
@drop="drop2('磁盘名',$event)"
// 在文件夹上方释放鼠标操作
drop(value,e,type){
  console.log("释放在",type,"磁盘中的",value,"文件夹中");
}
// 在磁盘上方释放鼠标操作
drop2(value,e){
  console.log("释放在",value,"磁盘中");
}

四、拖拽样式的实现

样式设计时,想要在文件拖入文件夹上方时给文件夹增加背景色,还要在文件拖入磁盘时给磁盘的边框加粗。相比于逻辑部分,拖拽的样式部分要繁琐很多,我最开始的写法如下:

//被拖入的元素
<div 
  @dragenter="dragenter($event)" 
  @dragleave="dragleave($event)"
  class=‘disk">
     <div 
     @dragenter="dragenter2($event)" 
	 @dragleave="dragleave2($event)"
	 class="folder">
		<div class="front"></div>
        <div class="center"></div>
        <div class="back"></div>
	</div>
</div>
// 进入磁盘上方时触发的函数
 dragenter(e) {
   console.log("被拖入的元素dom", e.target);
   e.target.classList.add("border");
 },
 // 离开磁盘上方时触发的函数
 dragleave(value, e) {
   console.log("离开的元素dom", e.target);
   e.target.classList.remove("border");
 },
// 进入文件夹上方时触发的函数
 dragenter2(e) {
   console.log("被拖入的元素dom", e.target);
   e.target.classList.add("hover-background");
 },
 // 离开文件夹上方时触发的函数
 dragleave2(value, e) {
   console.log("离开的元素dom", e.target);
   e.target.classList.remove("hover-background");
 },

但是测试时就发现了两个问题。
1、为文件夹元素增加dragenter事件,设置被拖入时增加背景色,但因为文件夹是由多个div组成,拖动到内部的div时,外部的div就不显示背景色了。
2、为磁盘元素增加dragenter事件,设置被拖入时增加border,但拖入到磁盘内其他元素中时都会为其增加border的效果。

根本原因在于
1、为外层元素添加的事件同样也会对内层的元素起作用。
2、拖动动作到内层元素后,会触发外层元素的dragleave事件。

也就是说即便拖动的元素还在磁盘内部,但因为已经进入了磁盘内文件夹的上方,那么对磁盘这个元素来说就已经触发了dragleave事件,对磁盘添加的border就已经不在了,而其内部的文件夹却被触发了dragenter事件而增加了border。

为了解决这个问题,是要记住最后一个dragenter的元素,因为进入其内部元素时,会先dragenter内部元素,紧接着dragleave外层元素,只要dragleave的元素和最后一个dragenter的元素相同即可

 dragenter2(e) {
   console.log("被拖入的元素dom", e.target);
   e.target.classList.add("hover-background");
   this.lastEnterFolder = e.target;
 },
 // 离开文件夹上方时触发的函数
 dragleave2(value, e) {
   console.log("dragleave", value, e.target);
   if (e.target == this.lastEnterFolder) {
     e.target.classList.remove("hover-background");
   }
 },

或者直接对内部元素的样式设置

//鼠标对其的任何动作都会被禁止
pointer-events: none;

最后来说一下在文件夹上方松开鼠标的时候,怎么把背景色取消掉,这就需要记住当前拖拽进的是哪个元素,并对这个元素删除掉其hover-background的属性值了。

//重写该方法
dragenter2(value, e) {
   console.log("dragenter--", value, e.target);
   e.target.classList.add("hover-background");
   this.lastEnterFolder = e.target;
   //在确定进入的是文件夹的时候标记currentFolderWrapper
   if(e.target.className == 'folder hover-background'){
     this.currentFolderWrapper = e.target
   }
 },
// 文件夹释放鼠标操作
drop2(e){
   e.target.classList.remove("hover-background");
   this.currentFolderWrapper.classList.remove("hover-background");
}

大家有好的解决方法欢迎交流~~
笔者码字不易,大家的点赞、收藏就是笔者继续更新的动力🤗️~~

  • 1
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值