HTML Drag and Drop API

HTML 拖放 接口使应用程序能够在浏览器中使用拖放功能。

用户可以使用鼠标选择可拖放的元素,将这些元素拖放到可放置的元素上,然后通过释放鼠标按钮来放置它们。在拖动操作过程中,可拖放元素的半透明表示会跟随指针移动。

您可以自定义哪些元素可以成为可拖放的,可拖放元素产生的反馈类型,以及可放置的元素。

此 HTML 拖放概述包括接口描述、向应用程序添加拖放支持的基本步骤,以及接口的互操作性摘要。

概念与用法

从表面上看,拖放实际上有三种不同的用例:在页面内拖动元素、将数据从页面拖出,以及将数据拖入页面。它们在需求和实现上都有细微的差异。然而,拖放 API 提供了一个统一的模型来思考所有这些交互。

核心而言,拖动操作涉及三件事

  • 要拖动的项目
  • 要传输的底层数据
  • 放置目标

并非所有这三项都一定在你的控制之下,或者需要你自己定义它们

  • 当将外部数据拖入页面时,没有可拖动的项目需要定义(例如,可能是操作系统文件浏览器中的文件)。
  • 当在页面内拖动元素时,你通常不需要定义任何传输的数据;你只需要操作被拖动的元素。
  • 当从页面拖出时,没有放置目标需要定义。

我们将看看每种如何定义和使用。

拖动事件

HTML 拖放使用DOM 事件模型和从鼠标事件继承的拖动事件。在拖动操作期间,会触发多个事件类型,某些事件可能会触发多次,例如dragdragover事件。

Event 何时触发...
dragstart ...可拖动的项目开始被拖动。
drag ...可拖动的项目正在被拖动,每隔几百毫秒。
dragenter ...可拖动的项目进入该元素。
dragleave ...可拖动的项目离开该元素。
dragover ...可拖动的项目正在该元素上方拖动,每隔几百毫秒。
drop ...该元素是放置目标,并且可拖动的项目被放置在该元素上。
dragend ...可拖动的项目停止被拖动。

注意: dragstartdragdragend事件在被拖动的项目上触发,因此在从操作系统将文件拖入浏览器时可能不会触发。

同样,dragenterdragleavedragoverdrop事件在可能成为放置目标的元素上触发,因此在将项目从浏览器拖出时可能不会触发。

有关更多信息,请参阅拖动操作

可拖动的项目

在 HTML 中,图像、链接和选择内容默认是可拖动的。要使任意元素可拖动,请将draggable属性设置为"true"

html
<p id="p1" draggable="true">This element is draggable.</p>

此时,该元素已经具有拖动外观,尽管尚未定义任何行为

对于图像和链接,draggable默认为true,因此您只需将其设置为false即可禁用这些元素的拖动。对于不可拖动的元素,“拖动”手势通常会选择文本。

注意: 当元素被设置为可拖动时,其内部的文本或其他元素将无法通过单击和拖动鼠标进行正常选择。用户必须按住Alt键才能用鼠标选择文本,或使用键盘。

选择内容也是可拖动的。在这种情况下,源节点,即触发dragstartdragend等各种事件的节点,是拖动开始的文本节点。选择内容可以部分或完全包含多个节点,包括文本节点和元素节点,这些节点都被视为同时被拖动。

如前所述,要拖动的项目也可以是网页上不存在的内容——例如,操作系统文件浏览器中的文件。但是,只有网页上的项目才能触发dragstartdragend事件。

有关更多信息,请参阅拖动操作指南

拖动数据存储

您不能直接将 JavaScript 对象传输到任意网页,更不用说传输到外部应用程序了,因此要将数据传输进出网页,数据必须序列化为字符串(或作为File)。在拖放中,此字符串封装在DataTransferItem对象中,该对象还定义了一个特定的type——通常是 MIME 类型,如text/html——该类型定义了字符串应如何被解释。

每个拖放操作都有一个相关的拖动数据存储,它是一个DataTransfer对象,可以通过DragEventdataTransfer属性访问。对于默认可拖动的项目,如图像、链接和选择内容,拖动数据已由浏览器定义;对于使用draggable属性定义的自定义可拖动元素,您必须自己定义拖动数据。修改数据存储的唯一时间是在dragstart处理程序中——对于任何其他拖动事件的dataTransfer,数据存储是不可修改的。

setData()方法可用于向拖动数据添加项目,如下面的示例所示。

js
function dragstartHandler(ev) {
  // Add different types of drag data
  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,
  );
}

const p1 = document.getElementById("p1");
p1.addEventListener("dragstart", dragstartHandler);

此外,除了dragstart事件之外,您唯一可以读取数据存储的时间是在drop事件期间(允许放置目标检索数据)。对于所有其他事件,数据存储无法访问。

有关更多信息,请阅读处理拖动数据存储

放置目标

放置目标是用户可以放置被拖动项目的元素。默认情况下,大多数元素都不是放置目标,如果您释放拖动,会显示“弹回”动画,表示拖放失败。任何元素都可以通过取消在其上触发的dragover事件(使用preventDefault())来成为放置目标。

drop事件仅在放置目标上触发,并且是您可以读取拖动数据存储的唯一时间。

以下示例显示了一个最小有效放置目标,并结合了先前示例中的代码。

html
<p id="target">Drop Zone</p>
js
const target = document.getElementById("target");

// Cancel dragover so that drop can fire
target.addEventListener("dragover", (ev) => {
  ev.preventDefault();
});
target.addEventListener("drop", (ev) => {
  ev.preventDefault();
  const data = ev.dataTransfer.getData("text/plain");
  ev.target.append(data);
});

有关更多信息,请参阅指定放置目标

指南

拖放操作

描述了拖放操作期间发生的步骤,以及应用程序在每个处理程序中应该做什么。

处理拖动数据存储

描述了在拖放操作期间如何读写拖动数据存储。

文件拖放

一个实现接受文件拖放的基本界面的实践指南。

带有拖放功能的看板

一个实现涉及在网页内拖放元素的看板的实践指南。

接口

DragEvent

传递给拖动事件处理程序的事件对象。

DataTransfer

包含在上下文之间传输的任何数据,由文本项和文件项组成。最初为拖放设计,现在也用于其他上下文,如剪贴板 API

DataTransferItem

表示拖动数据存储中的一项,可以是文本项或文件项。

DataTransferItemList

表示拖动数据存储中DataTransferItem对象的列表。

示例

每个接口的参考页面也有单独的示例。

规范

规范
HTML

另见