HTML 拖放(Drag and Drop)接口使应用程序能够在Firefox和其他浏览器中使用拖放功能。例如,通过这些功能,用户可以使用鼠标选择可拖动元素,将元素拖动到可放置元素,并通过释放鼠标按钮来放置这些元素。可拖动元素的一个半透明表示在拖动操作期间跟随鼠标指针。
对于网站、扩展以及 XUL 应用程序来说,你可以自定义能够成为可拖拽的元素类型、可拖拽元素产生的反馈类型,以及可放置的元素。
此文档为 HTML 拖放的概述,包含了相关接口的说明、在应用程序中加入拖放支持的基本步骤,以及相关接口的使用简介。
拖拽事件
HTML 的 drag & drop 使用了 DOM event model 以及从mouse events 继承而来的 drag events 。一个典型的drag操作是这样开始的:用户用鼠标选中一个可拖动的(draggable)元素,移动鼠标到一个可放置的(droppable)元素,然后释放鼠标。
在操作期间,会触发一些事件类型,有一些事件类型可能会被多次触发(比如drag 和 dragover 事件类型)。
在拖拽行为中,一些事件类型会被触发,并且一些事件可能触发很多次,比如drag和dragover事件。
所有的 drag event types 有一个对应的 global event handler。每个拖动事件类型和拖动全局属性都有对应的描述文档。下面的表格提供了一个简短的事件类型描述,以及一个相关文档的链接。
| Event | On Event Handler | Fires when… |
|---|---|---|
drag |
ondrag |
当拖动元素或选中的文本时触发。 |
dragend |
ondragend |
当拖拽操作结束时触发 (比如松开鼠标按键或敲“Esc”键). (见结束拖拽) |
dragenter |
ondragenter |
当拖动元素或选中的文本到一个可释放目标时触发(见 指定释放目标)。 |
dragexit |
ondragexit |
当元素变得不再是拖动操作的选中目标时触发。 |
dragleave |
ondragleave |
当拖动元素或选中的文本离开一个可释放目标时触发。 |
dragover |
ondragover |
当元素或选中的文本被拖到一个可释放目标上时触发(每100毫秒触发一次)。 |
dragstart |
ondragstart |
当用户开始拖动一个元素或选中的文本时触发(见开始拖动操作)。 |
drop |
ondrop |
当元素或选中的文本在可释放目标上被释放时触发(见执行释放)。 |
注意当从操作系统向浏览器中拖动文件时,不会触发 dragstart 和dragend 事件。
接口
HTML 的拖拽接口有 DragEvent, DataTransfer, DataTransferItem 和DataTransferItemList。
DragEvent 接口有一个构造函数和一个 dataTransfer
属性,dataTransfer 属性是一个 DataTransfer 对象。 DataTransfer 对象包含了拖拽事件的状态,例如拖动事件的类型(如拷贝 copy 或者移动 move),拖动的数据(一个或者多个项)和每个拖动项的类型(MIME类型)。 DataTransfer 对象也有一些方法,可以向拖动数据中添加项或者删除项。 DragEvent 和 DataTransfer 接口应该仅有的接口来给应用程序添加 html 拖放功能。
但是,注意 Firefox 给 DataTransfer 添加了可能用到的一些扩展的功能,尽管这些扩展只在
Firefox 上才可用。每个DataTransfer 包含一个 items
属性,这个属性是一个 DataTransferItem 对象的列表。
一个web应用需要添加拖拽功能时,应当仅仅使用DragEvent和
DataTransfer接口即可。 然而,Firefox支持一些DataTransfer对象上的 Gecko-specific extensions,注意这些拓展仅仅适用于Firefox。
每一个 DataTransfer 对象代表一个单独的拖动项,每一项有一个 kind 属性,代表数据的
kind(string 或 file),还有一个 type 属性,代表数据项的type(例如MIME类型),另外,DataTransferItem 对象也包含了得到拖拽项的数据的方法。
DataTransferItemList 对象是 DataTransferItem 对象的列表。这个列表对象包含以下方法:向列表中添加拖动项,从列表中移除拖动项和清空列表中所有的拖拽项。
DataTransfer 和 DataTransferItem 接口的一个主要的不同在于,前者使用同步的 getData() 方法去得到一个拖拽项的数据,然后后者使用异步的 getAsString() 方法得到一个拖拽项的数据。
注意: DragEvent 和 DataTransfer 接口是所有桌面浏览器都支持的。但是, DataTransferItem 和DataTransferItemList 接口并不被所有浏览器支持。请移步 Interoperability 了解更多关于拖动行为的信息.
Gecko 专用接口
Mozilla 和 Firefox 支持一些不在标准拖放模型中的特性。 它们是一些帮助实现拖动多个项目和拖动非文本内容(如文件)的便捷函数。想要了解更多信息,请参见拖放多个项目。另外,请查看 DataTransfer 参考页以获取所有 Gecko 专有属性 和 Gecko 专有方法。
基础
这一部分提供了将拖放功能添加到应用程序的基本步骤的摘要。每节内容包含描述、简短的代码案例,以及额外的知识的链接。
确定什么是可拖动的
让一个元素被拖动需要添加 draggable 属性,再加上全局事件处理函数ondragstart,如下面的示例代码所示:
<script>
function dragstart_handler(ev) {
// Add the target element's id to the data transfer object
ev.dataTransfer.setData("text/plain", ev.target.innerText);
}
</script>
<p id="p1" draggable="true" ondragstart="dragstart_handler(event)">This element is draggable.</p>
查看更多 draggable 属性和拖动操作指南。
定义拖动数据
应用程序可以在拖动操作中包含任意数量的数据项。每个数据项都是一个 string 类型,典型的 MIME 类型,如:text/html。
每个 drag event 都有一个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) {
// Create an image and then use it for the drag image.
// NOTE: change "example.gif" to a real image URL or the image
// will not be created and the default drag image will be used.
var img = new Image();
img.src = 'example.gif';
ev.dataTransfer.setDragImage(img, 10, 10);
}
欲了解更多关于拖动图像的信息,见设置拖动图像。
定义拖动效果
dropEffect 属性用来控制拖放操作中用户给予的反馈。它会影响到拖动过程中浏览器显示的鼠标样式。比如,当用户悬停在目标元素上的时候,浏览器鼠标也许要反映拖放操作的类型。
有 3 个效果可以定义:
copy表明被拖动的数据将从它原本的位置拷贝到目标的位置。move表明被拖动的数据将被移动。link表明在拖动源位置和目标位置之间将会创建一些关系表格或是连接。
在拖动过程中,拖动效果也许会被修改以用于表明在具体位置上具体效果是否被允许,如果允许,在该位置则被允许放置。
以下例子表明如何使用该属性。
function dragstart_handler(ev) {
ev.dataTransfer.dropEffect = "copy";
}
查看 拖动效果 更多细节。
定义一个放置区
当拖动一个项目到 HTML 元素中时,浏览器默认不会有任何响应。想要让一个元素变成可释放区域,该元素必须设置 ondragover 和 ondrop 事件处理程序属性,下面的例子通过简单的事件处理展示了如何使用这些属性,
<script>
function dragover_handler(ev) {
ev.preventDefault();
ev.dataTransfer.dropEffect = "move";
}
function drop_handler(ev) {
ev.preventDefault();
// Get the id of the target and add the moved element to the target's DOM
var data = ev.dataTransfer.getData("text/plain");
ev.target.appendChild(document.getElementById(data));
}
</script>
<p id="target" ondrop="drop_handler(event)" ondragover="dragover_handler(event)">Drop Zone</p>
注意每个处理程序调用 preventDefault() 来阻止对这个事件的其它处理过程(如触点事件或指针事件)。
欲了解更多信息,参见指定释放目标。
处理放置效果
drop 事件的处理程序是以程序指定的方法处理拖动数据。一般,程序调用 getData() 方法取出拖动项目并按一定方式处理。程序意义根据 dropEffect 的值与/或可变更关键字的状态而不同
下面的例子展示了一个处理程序,从拖动数据中获取事件源元素的id然后根据id移动源元素到目标元素
<script>
function dragstart_handler(ev) {
// Add the target element's id to the data transfer object
ev.dataTransfer.setData("application/my-app", ev.target.id);
ev.dataTransfer.dropEffect = "move";
}
function dragover_handler(ev) {
ev.preventDefault();
ev.dataTransfer.dropEffect = "move"
}
function drop_handler(ev) {
ev.preventDefault();
// Get the id of the target and add the moved element to the target's DOM
var data = ev.dataTransfer.getData("application/my-app");
ev.target.appendChild(document.getElementById(data));
}
</script>
<p id="p1" draggable="true" ondragstart="dragstart_handler(event)">This element is draggable.</p>
<div id="target" ondrop="drop_handler(event)" ondragover="dragover_handler(event)">Drop Zone</div>
更多信息请参见执行释放。
拖动结束
拖动操作结束时,在源元素(开始拖动时的目标元素)上触发dragend事件。不管拖动是完成还是被取消这个事件都会被触发。dragend事件处理程序可以检查
dropEffect属性的值来确认拖动成功与否。
更多关于处理拖动结束的信息请参见结束拖动。
互操作性
在数据交换对象接口的浏览器兼容性表中可以看到拖放在桌面浏览器中相对支持得比较完整(除了 DataTransferItem 和 DataTransferItemList 接口支持得较少)。这个数据也显示出拖放操作在移动浏览器中支持得非常弱。
示例和演示
- 使用
DataTransfer接口拷贝和移动元素 - 使用
DataTransferListItem接口拷贝和移动元素 - 拖放文件;仅 Firefox 支持:jsfiddle.net/9C2EF/
- 拖放文件;所有浏览器支持:jsbin.com/hiqasek/
- 使用了拖放API的停车小页面:park.glitch.me/ (在这里编辑)