拖拽有两种实现方式:
其中,H5 不仅移动 html 元素,还移动数据对象。要移动元素,推荐使用 MouseEvents:
- mousedown:选中元素
- mousemove:移动元素
- mouseup:释放元素
MouseEvent 方式
1 | // 简单实现一个拖拽 |
最佳实践见:鼠标拖放事件。
H5 Drag&Drop API
开始拖拽
设置 draggable 属性,监听 dragstart 事件。
draggable 属性
所有 HTML 元素都可以设置 draggable 属性。
取值:true、false、auto(取用户代理默认值,一般情况下选中文本、图片、链接默认可拖拽)。
具有 draggable 属性的元素还应该具有 title 属性,该标题属性用于非视觉交互的目的。
拖拽数据
event.dataTransfer接口
1 | [Exposed=Window,Constructor] // 暴露给 window 对象, |
拖拽事件
事件名 | e.target | 是否可取消 | 数据存储模式 | dropEffect | 默认行为 |
---|---|---|---|---|---|
dragstart | 源节点 | 可取消 | read/write | “none” | 启动拖放操作 |
drag | 源节点 | 可取消 | protected | “none” | 继续拖放操作 |
dragenter | 用户直接指定的可drop元素或body元素 | 可取消 | protected | 取决于 effectAllowed | 拒绝用户直接指定的可drop元素作为潜在目标元素 |
dragexit | 上一个目标元素 | - | protected | “none” | None |
dragleave | 上一个目标元素 | - | protected | “none” | None |
dragover | 当前目标节点 | 可取消 | protected | 取决于 effectAllowed | 将当前拖动操作重置为”none” |
drop | 当前目标节点 | 可取消 | read | 当前拖动操作 | 不定 |
dragend | 源节点 | - | protected | 当前拖动操作 | 不定 |
说明:
- 是否可取消:
e.cancelable
只读属性,如果事件不可取消,则其cancelable
属性将为false
,并且事件侦听器无法停止事件的发生;要取消事件,请对该事件调用preventDefault()
方法;取消后事件相当于没发生一样。 DragEvent
对象,继承自MouseEvent
,只多了一个独有的DataTransfer
属性。- dragenter 只在进入可 drop 元素时触发一次;dragover 只要没离开可 drop 元素,就会一直触发。
- dragleave 与 dragenter 对应。
- dragexit:当元素不再是拖动操作的立即选择目标时,将触发dragexit事件。(????)
- 所有这些事件都会冒泡,并且 effectAllowed 属性始终具有 dragstart 事件之后的值,在 dragstart 事件中默认为“uninitialized”。
结束拖拽
当拖动一个项目到 HTML 元素中时,浏览器默认不会有任何响应。想要让一个元素变成可释放区域,该元素必须设置 dragover 和 drop 事件处理程序属性。且 dragover 监听时要调用 e.preventDefault()
(注意每个处理程序调用 preventDefault() 来阻止对这个事件的其它处理过程)。
在网页中,如果监听了 drop 事件,应该调用事件的 preventDefault() 来阻止默认操作。例如,当将链接拖到网页上时,Firefox将打开该链接。通过取消事件,将防止此行为。
dragend 事件:源节点上触发。不管拖动是完成还是被取消这个事件都会被触发。
drop 事件:目标节点上触发。该元素必须设置 dragover 和 drop 事件处理程序属性,且阻止了 dragover 默认行为才会触发。
1 | function dragOverHandler(e) { |
何时使用
如果你只需要移动 HTML 元素,请使用 MouseEvent 方式。
如果你想转移数据对象,请使用 HTML5 Drag & Drop。
一些注意的点
为了拖拽时不触发拖拽内容的事件或者能正确的结束拖拽操作(如拖拽内容是嵌入的 iframe 时,鼠标在里面释放触发不了 mouseup 事件),一般在拖拽开始时加一个全透明的拖拽覆盖层来屏蔽事件和冒泡结束事件,拖拽结束时隐藏该层。
在 firefox 上拖拽结束时会打开一个新的标签页,可做如下处理:
1 | document.body.ondrop = function (e) { |
第三方拖拽库
https://github.com/SortableJS/Sortable
https://github.com/SortableJS/Vue.Draggable