拖放功能的实现及相关问题

拖放功能是指通过拖拽将一个元素从一个区域放置到另一个区域的功能。通常应用于将文件或图片从一个区域拖放到另一个区域。在中文中,常常被称为拖拽功能,但实际上应该称为拖放,因为drag事件和drop事件是成对使用的,即拖拽和放置。

drag事件在拖拽动作发生时触发,携带被拖拽元素的信息;而drop事件在放置元素时触发,接收传递的拖拽元素的信息。

一些人在实现拖动功能时可能误以为会触发drag事件,但实际上drag是为拖放功能设计的(需要配合drop)。拖动功能应该使用mousemove事件去实现,使用错误的事件会导致拖拽功能难以实现。


P.S.


drag和mousemove事件都是在鼠标移动的过程中触发,因此这两个事件可能会发生冲突。如果其中一个事件没有触发,可能是因为有元素绑定了另一个事件,导致另一个事件没有触发。

具体实现

要实现拖放功能,需要一个拖拽的区域和一个放置的区域。


首先,要定义允许拖拽的元素。

浏览器默认允许拖拽的元素包括文本、图像和链接,即<p>、<img>、<a>标签是默认允许拖拽的。其他元素需要设置draggable=”true”属性才能允许拖拽。这个属性不允许简写,例如<div draggable></div>并不会生效。


其次,要定义拖拽的数据。

例如,拖拽的是文本,则设置成文本格式,并设置拖拽的数据内容。拖拽的是图片,则设置成图片格式,并设置数据内容。定义成图片格式时,鼠标旁边会显示一张设置的图片。拖拽数据可以有多个。

为拖拽的元素绑定dragstart事件,然后设置dataTransfer。示例代码如下:

function dragstart_handler(ev) {
  // 添加拖拽数据
  ev.dataTransfer.setData("text/plain", ev.target.innerText);
  ev.dataTransfer.setData("text/html", ev.target.outerHTML);
  ev.dataTransfer.setData(
    "text/uri-list",
    ev.target.ownerDocument.location.href,
  );
}

在拖放过程中,事件对象event中有一个dataTransfer属性,保存着拖放过程中的数据,以及一些属性和方法用于设置和操作这些数据。

常用到的属性和方法有:


dropEffect

:设置放置操作的类型,可以修改放置时鼠标的显示,例如设置成”none”,鼠标就会显示为禁止的样式。


effectAllowed

:设置拖放过程的操作类型,同样影响鼠标的显示。


setData()

:设置拖放的数据。一般会在dragstart事件中用到。一个事件中,setData可以设置多个数据。但同类型的数据只能添加一项,重复添加会被最后添加的覆盖。


getData()

:检索获取拖放的数据。一般会在drop事件中用到。

具体可以参考MDN文档。


最后,就是在drop区域中放置拖拽的元素。

一个代码示例:

function drop_handler(ev) {
  const data = ev.dataTransfer.getData("text/plain");
  ev.target.textContent = data;
}

这样,拖放就结束了,拖放功能也完成了。

在拖放过程中,会触发一些全局事件,具体请参考MDN文档。

一些问题

但是,这样实现拖放功能会存在一些体验问题,例如鼠标的样式显示可能不正确。


以下是一些可能的问题:


1. 禁止放置的区域没有显示禁止图标。

在区域上绑定dragover事件,设置

dataTransfer.dropEffect='none'

,并禁止默认行为

e.preventDefault()


2. 禁止放置的区域可以放置。

通常默认可以放置的区域是一些输入标签,比如<input>、<textarea>。在drop事件中,禁止默认行为

e.preventDefault()

可以禁止放置。


3. 拖拽过程和可放置区域中,鼠标显示禁止图标。

在经过或者放置的区域上,在dragover和dragenter事件中禁止默认行为

e.preventDefault()

,设置

dataTransfer



none

以外的值。


4. 拖拽图片时,鼠标旁边没有出现图片。

要在dragstart事件中,设置dataTransfer为图片类型才会显示一张图片。如果拖拽的不是图片,但希望拖拽时有拖拽元素的图片效果显示,也可以设置dataTransfer为图片,设置要显示的图片效果,然后再设置其他的数据。dataTransfer.setData()方法可以设置多个类型的数据。

这样拖放功能的实现基本就完善了。最后,可以在开始拖拽和放置的时候,可能会给拖拽元素和放置区域设置一些高亮的CSS效果,整个拖放功能的体验就会更流畅。


参考:

draggable属性:
draggable – HTML(超文本标记语言) | MDN

拖放API:
HTML 拖放 API – Web API | MDN

DataTransfer:
DataTransfer – Web API | MDN

未经允许不得转载:大白鲨游戏网 » 拖放功能的实现及相关问题