HTML5拖拽技术介绍
HTML5 的拖拽实现
前提:draggable
将需要拖放的元素设置为 draggable = 'true'(img 和 a 元素默认为 true)
一、拖放相关事件
1. 被拖动元素: ondragstart、ondrag、ondragend
ondragstart
:用户开始拖动元素时触发ondrag
:元素正在拖动时触发ondragend
:用户完成元素拖动后触发
2. 放置目标元素(容器): ondragenter、ondragover、ondragleave、ondrop
dragenter
:当被鼠标拖动的对象进入其容器范围内时触发此事件dragover
:当某被拖动的对象在另一对象容器范围内拖动时触发此事件dragleave
:当被鼠标拖动的对象离开其容器范围内时触发此事件drop
:在一个拖动过程中,释放鼠标键时触发此事件。- 源对象拖放到目标对象中,目标对象完全接受被拖拽对象时触发,可理解为在目标对象内松手时触发
注意:对于 dragover
和 drop
,默认地,数据/元素无法被放置到其他元素中。为了实现拖放,我们必须阻止元素的这种默认的处理方式: 调用 event.preventDefault();
二、数据的传递:dataTransfer
所有拖放事件的参数 DragEvent
中,都提供了一个数据传输对象: dataTransfer
,用于在源对象和目标对象之间传递数据。
DataTransfer
对象包含了拖拽事件的状态,例如拖拽事件的类型(如拷贝 copy 或者移动 move),拖拽的数据(一个或者多个项)和每个拖拽项的类型(MIME 类型)。 DataTransfer
对象也有向拖拽数据中添加或删除项目的方法。
参考链接:MDN : DataTransfer
1. dataTransfer的方法
setData(format, data)
该方法设置拖拽事件中要传递的数据,向 dataTransfer 中对象中存入数据。
接受两个参数:
format
:DOMString,表示要添加到 drag object的拖动数据的类型。例如text/plain、text/html、text/xml、text/uri-list
data
:DOMString,表示要添加到 drag object的数据。例如event.dataTransfer.setData('text/plain', 'hello world')
注:如果给定类型的数据不存在,则将其添加到拖动数据存储的末尾,使得 dataTransfer.types 列表中的最后一个项目将是新类型。
getData(format)
该方法获得拖拽事件中传递的数据,从 dataTransfer
对象中读取数据
参数 format
为在 setData 方法中指定的数据类型,例如: event.dataTransfer.getData('text/plain')
clearData()
该方法清空 dataTransfer
对象中存储的数据,参数可选,为数据类型。若为空,则清空所有数据。
setDragImage(element, x, y)
该方法通过 img 元素来设置拖放图标
element
表示拖拽时鼠标下面的图片(通常是 image 元素,也可以说 canvas 元素)
x
、y
分别指示相对于图片的横向和纵向偏移量,相对应鼠标指针。
2. dataTransfer的属性
files 属性
返回被拖拽的文件列表,是一个 FileList 对象,有 length 属性,可通过下标访问。
如果拖动操作不涉及拖动文件,则此属性为空列表.
dropEffect 属性
获取当前选定的拖放操作类型或者设置的为一个新的类型。值必须为 none, copy, link 或 move
。
必须在 dragenter
事件处理函数中设置。
- none 不能把元素拖放至此(除文本框外全部元素的默认值)
- move 移动到目标
- copy 复制到目标
- link 目标打开拖动元素(拖动元素必须是链接并有 URL)
dropEffect 属性
提供所有可用的操作类型。必须是 none, copy, copyLink, copyMove, link, linkMove, move, all or uninitialized
之一。
必须在 dragstart
事件处理函数中设置。
- uninitialized 没有设置任何拖放行为
- none 不能由任何行为
- copy 仅允许 dropEffect 值为 copy
- link 仅允许 dropEffect 值为 link
- move 仅允许 dropEffect 值为 move
- copyLink 允许 dropEffect 值为 copy 和 link
- copyMove 允许 dropEffect 值为 copy 和 move
- linkMove 允许 dropEffect 值为 link 和 move
- all 允许任意 dropEffect
三、示例:HTML 拖拽示例 drag & drop
HTML 代码
<div class="drag-item" id="dragitem" draggable="true">被拖动元素</div>
<div class="target-area">
<div class="target" id="t1">目标元素</div>
<div class="target" id="t2">目标元素2</div>
</div>
<div class="status-area">
<div id="info">请拖动</div>
<div id="info2"></div>
</div>
JavaScript 代码
let item = document.getElementById('dragitem')
let info = document.getElementById('info')
let info2 = document.getElementById('info2')
let targets = document.getElementsByClassName('target')
item.addEventListener('dragstart', function(ev){
ev.target.style.background = "lightgreen";
ev.target.style.color = "black";
ev.target.style.opacity = 0.5;
info.innerHTML = "开始拖动";
// 设定传递数据
ev.dataTransfer.setData('itemid', ev.target.id)
})
item.addEventListener('dragend', function(ev){
ev.target.style.background = "black";
ev.target.style.color = "white";
info.innerHTML = "结束拖动";
ev.target.style.opacity = 1;
info2.innerHTML = "";
})
item.addEventListener('drag', function(ev){
info2.innerHTML = "拖动中";
})
for(let target of targets) {
target.addEventListener('dragover', function(ev) {
//默认地,数据/元素无法被放置到其他元素中。
//为了实现拖放,我们必须阻止元素的这种默认的处理方式
ev.preventDefault();
})
target.addEventListener('dragenter', function(ev) {
ev.target.style.border = "3px dotted red";
})
target.addEventListener('dragleave', function(ev) {
ev.target.style.border = "1px solid black";
})
target.addEventListener('drop', function(ev) {
ev.preventDefault();
let id = ev.dataTransfer.getData('itemid')
ev.target.appendChild(document.getElementById(id))
})
target.addEventListener('dragover', function(ev) {
ev.preventDefault();
ev.target.style.border = "3px dotted red";
})
}