此文研究Web API中的拖放接口,提供各个属性和方法的说明,解决拖放过程当中的拖拽数据对象存储和获取问题。html
拖放API做用到两个目标对象,分别是拖拽目标对象和放置目标对象。segmentfault
一个设置draggable
属性的值为true
DOM元素或者一个选中状态的文本区块能够成为拖拽目标。数组
<div draggable="true"></div>
ORapp
一个绑定了下图放置目标对应的5个事件的DOM元素能够成为放置目标。函数
拖放API有8个事件,其中有3个事件绑定在拖拽目标上,有5个事件绑定在放置目标上。spa
Evnet | Description |
---|---|
dragstart | 当用户开始拖拽一个元素或者一个文本选取区块的时触发。 |
drag | 当用户正在拖拽一个元素或者一个文本选取区块的时触发。 |
dragend | 当用户结束拖拽一个元素或者一个文本选取区块的时触发。(如放开鼠标按键或按下键盘的 escap 键) |
Event | Description |
---|---|
dragenter | 当一个元素或文字选取区块被拖曳移动进入一个有效的放置目标时触发。 |
dragover | 当一个元素或文字选取区块被拖曳移动通过一个有效的放置目标时触发。 |
dragleave | 当一个元素或文字选取区块被拖曳移动离开一个有效的放置目标时触发。 |
dragexist | 当一个元素再也不是被选取中的拖曳元素时触发。(Firefox能触发,触发顺序:dragexist->dragleave->drop;Chrome没法触发) |
drop | 当一个元素或文字选取区块被放置至一个有效的放置目标时触发。 |
经过下图能更直观观察每一个事件触发的时机.net
戳我看源码3d
注意:在dragover事件中使用
event.preventDefault();
阻止默认事件,才能触发drop事件code
在进行拖放操做时,会触发上面所述的8个事件,每一个event事件对象中都会有DataTransfer对象用来保存被拖动的数据。它能够保存一项或多项数据、一种或者多种数据类型。htm
用来指定拖动时被容许的效果。
在dragstart事件中设置
设置实际的放置效果,它应该始终设置成effectAllowed的可能值之一 。
在dragenter事件和dragover事件中设置
effectAllowed和dropEffect属性的栗子:戳我看源码
包含一个在数据传输上全部可用的本地文件列表。若是拖动操做不涉及拖动文件,此属性是一个空列表。
filesZoneEl.addEventListener("drop", (event) => { event.preventDefault(); let files = event.dataTransfer.files; for (let i = 0, len = files.length; i < len; i++) { let liEl = document.createElement("li"); liEl.innerHTML = files[i].name; filesListEl.appendChild(liEl); } });
保存一个被存储数据的类型列表做为第一项,顺序与被添加数据的顺序一致。若是没有添加数据将返回一个空列表。
存储DataTransferItem数据对象的列表。
设置拖动源。
event.dataTransfer.addElement(element);
为一个给定的类型设置数据并存储在items属性中。
从items属性中获取给定类型的数据,无数据时返回空字符串。
event.dataTransfer.getData(type);
从items属性中删除与给定类型关联的数据,若类型为空则删除全部数据。
event.dataTransfer.clearData(type);
自定义一个指望的拖动时的图片,默认为被拖动的节点。
event.dataTransfer.setDragImage(imgElement, offsetX, offsetY);
Param | Description |
---|---|
imgElement | 要用做拖动反馈图像元素。 |
offsetX | 图像内的水平偏移量。 |
offsetY | 图像内的垂直偏移量。 |
设置拖动时的图片时,要把图片预加载,不然图片会在拖动开始dragstart事件触发时才会加载图片,会致使拖动图出不来或闪一下的后果。可把图片放到<img>
标签并设置display:none;
,原理详看我以前的文章Web图片资源的加载与渲染时机。
dataTramsfer对象的items属性,包含了一系列DataTransferItem拖拽数据对象。
数组长度。
增长一个拖拽数据对象到items属性中,并返回增长的拖拽数据对象。
event.dataTransfer.items.add(file);
从items属性中移除指定位置的一个拖拽数据对象。
event.dataTransfer.items.remove(index);
清空items属性中的所拖拽数据对象。
event.dataTransfer.items.clear();
DataTransferItemList列表中的拖拽数据对象。
拖拽数据对象类型。
Value | Description |
---|---|
file | 文件类型。 |
string | 文本字符串类型。 |
MIME类型的Unicode字符串,例如text/plain、text/html或image/png。
若拖拽数据对象是文件类型,则返回一个文件对象。
let itemList = event.dataTransfer.items; for (let i = 0, len = itemList.length; i < len; i++) { if (itemList[i].kind == "file") { console.log(itemList[i].getAsFile()); } }
若拖拽数据对象是文本字符串类型,经过回调函数获取拖拽数据中的字符串数据。
let itemList = event.dataTransfer.items; for (let i = 0, len = itemList.length; i < len; i++) { if (itemList[i].kind == "string") { itemList[i].getAsString((data) => { console.log(data); }); } }
在进行拖放操做时,有可能须要把拖拽目标的数据传送给放置目标,此时通常操做是在dragstart事件触发时把须要的数据存储到一个变量,而后再drop事件触发时获取这个变量。但当dragstart事件和drop事件在不一样的文件定义,又不想玷污全局变量的状况下,咱们须要更好的办法来存储拖放数据。
在DataTransfer对象中的items属性就是用来存储拖放数据的,数据类型分为文本类型和文件类型。
event.dataTransfer.setData(type, data);
OR
event.dataTransfer.items.add(data, type);
一种文本字符串类型只能存储一个数据,当重复文本字符串类型存储数据时,后者会覆盖前者。
event.dataTransfer.items.add(file);
event.dataTransfer.types
let files = event.dataTransfer.files; for (let i = 0, len = files.length; i < len; i++) { console.log(files[i]); }
OR
let itemList = event.dataTransfer.items; for (let i = 0, len = itemList.length; i < len; i++) { if (itemList[i].kind == "file") { console.log(itemList[i].getAsFile()); } }
let itemList = event.dataTransfer.items; for (let i = 0, len = itemList.length; i < len; i++) { if (itemList[i].kind == "string") { itemList[i].getAsString((data) => { console.log(data); }); } }
event.dataTransfer.getData(type);
event.dataTransfer.clearData(type);
event.dataTransfer.items.remove(index);
event.dataTransfer.clearData();
OR
event.dataTransfer.items.clear();
上面的几个栗子都使用了以上方法存储和获取拖拽数据对象,感兴趣的能够看看源码。
欢迎关注:Leechikit
原文连接:segmentfault.com到此本文结束,欢迎提问和指正。写原创文章不易,若本文对你有帮助,请点赞、推荐和关注做者支持。