HTML5 Drag and Drop
全面理解Drag & Drop API
元素的拖放(Drag and Drop)在Web页面上也是一个常见的特性,即抓取一个对象拖动并将其放到另一个位置;HTML5将其标准化:任何页面元素都可以被拖动。
HTML5拖放的浏览器支持情况如下:
API | Chrome | IE | Firefox | Safari | Opera |
---|---|---|---|---|---|
Drag and Drop | 4.0 | 9.0 | 3.5 | 6.0 | 12.0 |
draggable 属性
draggable
属性是HTML5新增的一个属性,指定一个元素是否可以被拖动,所有HTML元素都可以设置该属性;draggable
属性可以设置的值如下所示:
- true:元素可以拖动
- false:元素不可以拖动
- auto:使用浏览器默认行为
默认情况下,图片和链接两种元素是可以拖动的
下面两个段落中的第二个将 draggable
属性设置为true后,可以看到该段落可以拖动了,鼠标移到上面后指针也不再变化,只是好像不能再选择文字了。
不可拖动的段落
可以拖动的段落
拖放相关事件
在元素的拖放过程会触发一系列事件,我们正是使用这些事件来响应拖放操作的;这些事件可以分为两类:拖动元素(拖放源)事件和放置元素(拖放目标)事件。
被拖动元素上触发的事件
dragstart
:用户开始拖动一个元素时触发drag
:元素正在被拖动时触发dragend
:用户结束元素拖动时触发
触发dragstart事件后,其他元素的鼠标事件诸如 mousemove、mouseover、mouseout 等事件均不会被触发了。
注意,拖动元素时,drag事件每350毫秒触发一次
放置元素上触发的事件
dragenter
:当被拖动元素进入目标元素时触发dragover
:被拖动元素在目标元素上移动时触发dragleave
:被拖动元素离开目标元素时触发drop
:被拖动元素放在目标元素时触发(在目标元素上松开鼠标)
dragover事件是被拖拽元素在目标元素上移动一段时间后才触发,因此该事件并不会与dragenter事件一起被触发。
从上面的解释可以了解到,一个拖放过程应该是这样的:dragstart –> dragenter –> dragover –> drop –> dragend
DataTransfer 对象
DataTransfer
对象用于配置拖拽行为效果,并且在拖拽过程的各事件间传递数据,传递的数据类型被限定为字符串和文件类型;DataTransfer
对象作为一个属性存储在拖拽事件对象(DragEvent)中,DragEvent继承自MouseEvent,其实就比MouseEvent多了一个 DataTransfer
对象属性。
DataTransfer的属性
effectAllowed
effectAllowed
属性用于设置被拖拽元素可执行的操作。
该属性可以设置的值如下:
可用值 | 说明 |
---|---|
copy | 限定dropEffect的属性值为copy,否则会鼠标指针为禁止样式 |
link | 限定dropEffect的属性值为link,否则会鼠标指针为禁止样式 |
move | 限定dropEffect的属性值为move,否则会鼠标指针为禁止样式 |
copyLink | 限定dropEffect的属性值为copy和link,否则会鼠标指针为禁止样式 |
copyMove | 限定dropEffect的属性值为copy和move,否则会鼠标指针为禁止样式 |
linkMove | 限定dropEffect的属性值为link和move,否则会鼠标指针为禁止样式 |
all | 允许dropEffect的属性值为任意值 |
none | 鼠标指针一直为禁止样式,不管dropEffect的属性值是什么 |
uninitialized | 没有限定dropEffect属性的值,效果和 all 一样 |
仅能在 dragstart 事件中设置该属性,其他事件中设置均无效。
dropEffect
dropEffect
属性用于设置目标元素将执行的操作,若属性值属于 effectAllowed
范围内,则鼠标指针将显示对应的指针样式,否则则显示禁止的指针样式。
该属性的取值及意义如下:
可用值 | 说明 |
---|---|
copy | 被拖拽元素将被复制到目标元素内,若属于 effectAllowed 范围内时,则鼠标指针显示复制的样式,否则则显示禁止的指针样式。 |
link | 被拖拽元素将以超链接的形式打开资源,若属于 effectAllowed 范围内时,则鼠标指针显示超链接的样式,否则则显示禁止的指针样式。 |
move | 被拖拽元素将被移动到目标元素内,若属于 effectAllowed 范围内时,则鼠标指针显示移动的样式,否则则显示禁止的指针样式。 |
none | 被拖拽元素不能在目标元素上作任何操作,一直显示禁止的指针样式。除了文本框外其他元素的默认值均为none |
仅能在 dragover 事件中设置该属性值,其他事件中设置均无效
当显示禁止的指针样式时,将无法触发目标元素的 drop 事件。
items
items
属性数据类型为 DataTransferItemList
,存储 DataTransfer
对象中所有的数据项。目前只有Chrome浏览器支持该属性。
DataTransferItemList
是个类数组的类型,可以使用索引引用数据项,也有length属性;另外还有clear()和add()方法。
files
files
属性数据类型为FileList
types
types
属性数据类型为DOMStringList,存储DataTransfer对象中所有数据项的数据类型。
仅能在dragenter,dragover和drop中获取该属性
DataTransfer的方法
addElement()
void addElement({HTMLElement} element)
方法用于添加一起跟随鼠标移动的元素。
addElement()
方法仅在 dragstart
事件中可以调用。
setDragImage()
void setDragImage({Element} image, {long} x, {long} y)
方法用于设置拖动时跟随鼠标移动的图片,用来替代默认的元素;若image参数不是图片元素则会将元素临时转换为图片;x和y分别用于设置图标与鼠标指针在水平方向和垂直方向上的距离。
setDragImage()
方法仅在 dragstart
事件中可以调用。
image参数必须在DOM树中,而且在渲染树中为有效元素,即display不为none,否则会导致没有元素跟随鼠标移动
setData()
boolean setData({DOMString} format, {DOMString} data)
方法将指定格式的数据赋值给dataTransfer或clipboardData,format值范围为URL、Text(或text)和各种MIME类型,其实Text会被自动映射为text/plain,URL会被自动映射为text/uri-list类型。
setData()
方法仅在 dragstart
事件中可以调用。
当没有填写第二个入参时,则会根据format来删除相应的数据项
getData()
DOMString getData({DOMString} format)
方法从DataTransfer对象或ClipboardData对象中获取指定格式的数据。
clearData()
void clearData([{DOMString} format])
方法从DataTransfer对象或ClipboardData对象中删除指定格式或全部kind值为string的数据。
仅在 dragstart
事件中调用,在其他事件中调用会抛InvalidStateError。
数据存储模式
- Read/Write(读写)模式:
dragstart
事件为该模式,可读写数据 - Read-only(只读)模式:在
drop
事件为该模式,仅能读取数据 - Protected(保护)模式:其他事件为该模式,仅能枚举数据
示例
简单的拖放
下面是一个简单的元素拖放示例,仅仅是将一个p元素拖到div元素中。
|
|
把我拖到下面方框试试
首先给p元素添加一个 dragstart
事件监听,在监听函数中向 DataTransfer
对象设置了Text类型的数据,值是被拖动元素的ID。
接下来给目标元素添加了 dragover
事件监听,默认情况下,无法将数据/元素放置到其他元素中,如果设置为允许放置,我们必须阻止对元素的默认处理方式,也就是调用 DragEvent
事件对象的 preventDefault()
方法。
最后又给目标元素设置了 drop
事件监听,用来响应拖动元素放下的动作;调用事件对象的 preventDefault()
方法来避免浏览器对数据的默认处理(drop 事件的默认行为是以链接形式打开);接着获取存在 DataTransfer
对象中的数据(拖动元素的ID),然后将该元素追加到目标元素中。
复制元素
接下来再写一个示例,也很简单,与上一个示例区别就是这次不是移动元素,而是将元素复制一份加入目标元素,拖动过程中注意看鼠标指针的变化。
|
|
把我拖到下面方框试试
代码与上一个示例相差无几,主要区别在于以下两点:
dragstart
事件监听函数中将DataTransfer
对象的effectAllowed
属性设置为 copyMove;dragover
事件监听函数中将DataTransfer
对象的dropEffect
属性设置为copy;
这样就可以在拖拽元素拖到目标元素上时改变鼠标指针,最后在 drop
事件监听函数中复制一份拖拽元素并加入目标元素中。