HTML Drag and Drop API
HTML 拖放 接口使应用程序能够在浏览器中使用拖放功能。
用户可以使用鼠标选择可拖放的元素,将这些元素拖放到可放置的元素上,然后通过释放鼠标按钮来放置它们。在拖动操作过程中,可拖放元素的半透明表示会跟随指针移动。
您可以自定义哪些元素可以成为可拖放的,可拖放元素产生的反馈类型,以及可放置的元素。
此 HTML 拖放概述包括接口描述、向应用程序添加拖放支持的基本步骤,以及接口的互操作性摘要。
概念与用法
从表面上看,拖放实际上有三种不同的用例:在页面内拖动元素、将数据从页面拖出,以及将数据拖入页面。它们在需求和实现上都有细微的差异。然而,拖放 API 提供了一个统一的模型来思考所有这些交互。
核心而言,拖动操作涉及三件事
- 要拖动的项目
- 要传输的底层数据
- 放置目标
并非所有这三项都一定在你的控制之下,或者需要你自己定义它们
- 当将外部数据拖入页面时,没有可拖动的项目需要定义(例如,可能是操作系统文件浏览器中的文件)。
- 当在页面内拖动元素时,你通常不需要定义任何传输的数据;你只需要操作被拖动的元素。
- 当从页面拖出时,没有放置目标需要定义。
我们将看看每种如何定义和使用。
拖动事件
HTML 拖放使用DOM 事件模型和从鼠标事件继承的拖动事件。在拖动操作期间,会触发多个事件类型,某些事件可能会触发多次,例如drag和dragover事件。
| Event | 何时触发... |
|---|---|
dragstart |
...可拖动的项目开始被拖动。 |
drag |
...可拖动的项目正在被拖动,每隔几百毫秒。 |
dragenter |
...可拖动的项目进入该元素。 |
dragleave |
...可拖动的项目离开该元素。 |
dragover |
...可拖动的项目正在该元素上方拖动,每隔几百毫秒。 |
drop |
...该元素是放置目标,并且可拖动的项目被放置在该元素上。 |
dragend |
...可拖动的项目停止被拖动。 |
注意: dragstart、drag和dragend事件在被拖动的项目上触发,因此在从操作系统将文件拖入浏览器时可能不会触发。
同样,dragenter、dragleave、dragover和drop事件在可能成为放置目标的元素上触发,因此在将项目从浏览器拖出时可能不会触发。
有关更多信息,请参阅拖动操作。
可拖动的项目
在 HTML 中,图像、链接和选择内容默认是可拖动的。要使任意元素可拖动,请将draggable属性设置为"true"。
<p id="p1" draggable="true">This element is draggable.</p>
此时,该元素已经具有拖动外观,尽管尚未定义任何行为
对于图像和链接,draggable默认为true,因此您只需将其设置为false即可禁用这些元素的拖动。对于不可拖动的元素,“拖动”手势通常会选择文本。
注意: 当元素被设置为可拖动时,其内部的文本或其他元素将无法通过单击和拖动鼠标进行正常选择。用户必须按住Alt键才能用鼠标选择文本,或使用键盘。
选择内容也是可拖动的。在这种情况下,源节点,即触发dragstart和dragend等各种事件的节点,是拖动开始的文本节点。选择内容可以部分或完全包含多个节点,包括文本节点和元素节点,这些节点都被视为同时被拖动。
如前所述,要拖动的项目也可以是网页上不存在的内容——例如,操作系统文件浏览器中的文件。但是,只有网页上的项目才能触发dragstart和dragend事件。
有关更多信息,请参阅拖动操作指南。
拖动数据存储
您不能直接将 JavaScript 对象传输到任意网页,更不用说传输到外部应用程序了,因此要将数据传输进出网页,数据必须序列化为字符串(或作为File)。在拖放中,此字符串封装在DataTransferItem对象中,该对象还定义了一个特定的type——通常是 MIME 类型,如text/html——该类型定义了字符串应如何被解释。
每个拖放操作都有一个相关的拖动数据存储,它是一个DataTransfer对象,可以通过DragEvent的dataTransfer属性访问。对于默认可拖动的项目,如图像、链接和选择内容,拖动数据已由浏览器定义;对于使用draggable属性定义的自定义可拖动元素,您必须自己定义拖动数据。修改数据存储的唯一时间是在dragstart处理程序中——对于任何其他拖动事件的dataTransfer,数据存储是不可修改的。
setData()方法可用于向拖动数据添加项目,如下面的示例所示。
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事件仅在放置目标上触发,并且是您可以读取拖动数据存储的唯一时间。
以下示例显示了一个最小有效放置目标,并结合了先前示例中的代码。
<p id="target">Drop Zone</p>
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 |