HTML Drag and Drop API - 使应用程序能够在浏览器中使用拖放功能

HTML 拖放接口使应用程序能够在浏览器中使用拖放功能。用户可以使用鼠标选择可拖动元素,将这些元素拖动到可放置元素,然后通过释放鼠标按钮来放置它们。在拖动操作过程中,可拖动元素会以半透明的表现形式会跟随指针移动。

对于网站、扩展和 XUL 应用程序,您可以自定义哪些元素可以变为可拖动元素、可拖动元素产生的反馈类型以及可放置元素。

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

拖动事件

HTML 拖放使用DOM 事件模型和从鼠标事件继承的拖动事件。典型的拖动操作开始于用户选择可拖动元素,将元素拖动到可放置元素,然后释放被拖动元素。

在拖动操作期间,会触发多种事件类型,并且某些事件可能会触发多次,例如 dragdragover 事件。

每个拖动事件类型 都有一个关联的全局事件处理程序

事件 事件处理程序 触发时机
drag ondrag 拖动的项目(元素或选择的文本)被拖动。
dragend ondragend 当拖动操作结束(例如释放鼠标按钮或按 Esc 键;请参阅完成拖动。)
dragenter ondragenter 当拖动的项目进入有效的放置目标。(请参阅指定放置目标。)
dragexit ondragexit 当元素不再是拖动操作的直接选择目标。
dragleave ondragleave 当拖动的项目离开有效的放置目标时。
dragover ondragover 当拖动的项目被拖动到有效的放置目标上时,每次隔几百毫秒。
dragstart ondragstart 当用户开始拖动项目时。(请参阅开始拖动操作。)
drop ondrop 当一个项目被放置在一个有效的放置目标上时。(请参阅执行放置。)

注意: 将文件从操作系统拖入浏览器时,不会触发 dragstartdragend 事件。

接口

HTML 拖放接口包含了 DragEventDataTransferDataTransferItemDataTransferItemList.

DragEvent 接口有一个构造函数和一个 dataTransfer 属性,它是一个 DataTransfer 对象。

DataTransfer 对象包括拖动事件的状态,例如正在完成的拖动类型(如 copymove)、拖动的数据(一个或多个项目)和每个拖动项目的 MIME 类型。DataTransfer 对象还具有向拖动数据添加或删除项目的方法。

DragEventDataTransfer 接口应该是向应用程序添加 HTML 拖放功能所需的唯一接口。(Firefox 向 DataTransfer 对象添加了一些特定的扩展,注意这些扩展仅适用于 Firefox。)

每个 DataTransfer 对象都包含一个 items 属性,它是一个包含 DataTransferItem 对象的列表。一个 DataTransferItem 对象代表一个拖动项目,每个对象都有一个 kind 属性(stringfile)和一个 type 属性表示数据项的 MIME 类型。DataTransferItem 对象也有获取拖动项数据的方法。

DataTransferItemList 对象是一个包含 DataTransferItem 对象的列表。该对象具有向列表添加拖动项、从列表中删除拖动项以及清除所有拖动项的列表的方法。

DataTransferDataTransferItem 接口之间的主要区别在于前者使用同步 getData() 方法来访问拖动项的数据,但后者使用异步 getAsString() 方法。

注意: DragEventDataTransfer 在桌面浏览器上得到广泛支持。但是,DataTransferItemDataTransferItemList 接口的浏览器支持有限。有关拖放互操作性的更多信息,请参阅互操作性

特定于 Gecko 的接口

Mozilla 和 Firefox 支持标准拖放模型中没有的一些功能。这些是帮助拖动多个项目或非字符串数据(如文件)的便利功能。有关详细信息,请参阅 拖放多个项目。此外,请参阅 DataTransfer 参考页面,了解所有 Gecko 特有属性Gecko 特有方法

基础知识

本节总结了向应用程序添加拖放功能的基本步骤。

确定什么是可拖动

使元素可拖动,需要添加 draggable 属性和 ondragstart 全局事件处理程序,如以下代码实例所示:

<script>
  function dragstart_handler(ev) {
    // 将目标元素的 id 添加到数据传输对象
    ev.dataTransfer.setData("text/plain", ev.target.id);
  }

  window.addEventListener('DOMContentLoaded', () => {
    // 通过 id 获取元素
    const element = document.getElementById("p1");
    // 添加 ondragstart 事件监听器
    element.addEventListener("dragstart", dragstart_handler);
  });
</script>

<p id="p1" draggable="true">该元素是可拖动的。</p>

尝试一下 »

有关更多信息,请参阅:

定义拖动的数据

该应用程序可以自由地在拖动操作中包含任意数量的数据项。每个数据项都是一个特定 typestring —— 通常是一个 MIME 类型,例如 text/html

每个拖动事件都有一个 dataTransfer 属性,用于保存事件的数据。这个属性(它是一个 DataTransfer 对象)也有管理拖动数据的方法。setData() 方法用于向拖动数据添加项目,如下例所示。

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);
}
  • 有关拖放中使用的常见数据类型(例如文本、HTML、链接和文件)的列表,请参阅 推荐的拖放类型.
  • 有关拖动数据的更多信息,请参阅拖动数据

定义拖动的图像

默认情况下,浏览器提供在拖动操作期间出现在指针旁边的图像。但是,应用程序可以使用 setDragImage() 方法定义自定义图像,如下例所示。

function dragstart_handler(ev) {
  // 创建一个图像,然后将其用于拖动图像。
  // 注意: 将 "example.gif "改为真正的图像 URL,
  // 否则将不会创建图像,而会使用默认的拖动图像。
  let img = new Image();
  img.src = 'example.gif';
  ev.dataTransfer.setDragImage(img, 10, 10);
}

了解有关拖动反馈图像的更多信息:

定义拖动效果

dropEffect 属性用于控制在拖放操作期间向用户提供的反馈。它通常会影响浏览器在拖动时显示的光标。例如,当用户将鼠标悬停在放置目标上时,浏览器的光标可能会指示将发生的操作类型。

可以定义三种效果:

  1. copy 表示将拖动的数据从其当前位置复制到放置位置。
  2. move 表示拖动的数据将从当前位置移动到放置位置。
  3. link 表示将在源位置和放置位置之间创建某种形式的关系或连接。

在拖动操作期间,可以修改拖动效果以指示在某些位置允许某些效果。

以下实例显示了如何使用此属性。

function dragstart_handler(ev) {
  ev.dataTransfer.dropEffect = "copy";
}

有关更多详细信息,请参阅:

定义一个放置区域

默认情况下,当把内容放到大多数 HTML 元素上时,浏览器不会有任何的效果。要更改该行为以使元素成为放置区域可放置,该元素必须同时具有 ondragoverondrop 事件处理程序属性。

以下实例显示了如何使用这些属性,并包括每个属性的基本事件处理程序。

<script>
function dragover_handler(ev) {
 ev.preventDefault();
 ev.dataTransfer.dropEffect = "move";
}
function drop_handler(ev) {
 ev.preventDefault();
 // 获取目标的 id 并将移动的元素添加到目标的 DOM
 const data = ev.dataTransfer.getData("text/plain");
 ev.target.appendChild(document.getElementById(data));
}
</script>

<p id="target" ondrop="drop_handler(event)" ondragover="dragover_handler(event)">放置区域</p>

请注意,每个处理程序都会调用 preventDefault() 以防止对此事件(例如 触摸事件指针事件)进行额外的事件处理。

有关更多信息,请参阅:

处理放置效果

drop 事件的处理程序可以以特定于应用程序的方式自由处理拖动数据。

通常,应用程序使用 getData() 方法来获取拖动项,然后相应地处理它们。此外,应用程序语义可能因 dropEffect 的值和 / 或修饰键的状态而异。

以下实例显示了一个放置处理程序,它从拖动数据中获取源元素的 id,然后使用 id 将源元素移动到放置元素:

<script>
function dragstart_handler(ev) {
 // 将目标元素的 id 添加到数据传输对象
 ev.dataTransfer.setData("application/my-app", ev.target.id);
 ev.dataTransfer.effectAllowed = "move";
}
function dragover_handler(ev) {
 ev.preventDefault();
 ev.dataTransfer.dropEffect = "move"
}
function drop_handler(ev) {
 ev.preventDefault();
 // 获取目标的 id 并将移动的元素添加到目标的 DOM
 const data = ev.dataTransfer.getData("application/my-app");
 ev.target.appendChild(document.getElementById(data));
}
</script>

<p id="p1" draggable="true" ondragstart="dragstart_handler(event)">此元素是可拖动的。</p>
<div id="target" ondrop="drop_handler(event)" ondragover="dragover_handler(event)">放置区域</div>

尝试一下 »

有关更多信息,请参阅:

拖动结束

在拖动操作结束时,在元素(即拖动开始的目标元素)上会触发 dragend 事件。

无论拖动是完成还是取消,都会触发此事件。dragend 事件处理程序可以检查 dropEffect 属性的值来确定拖动操作是否成功。

有关处理拖动操作结束的更多信息,请参阅:

互操作性

DataTransferItem 接口的浏览器兼容性表 中可以看出,桌面浏览器之间的拖放互操作性比较广泛(除了 DataTransferItemDataTransferItemList 接口支持较少)。该数据还表明移动浏览器之间的拖放支持非常低。

实例和演示

规范

规范 状态 备注
HTML Living Standard 现行的标准 -

相关链接