# DataTransfer 对象
# 介绍
DataTransfer 对象出现在拖拽事件中,具体包括开始拖拽dragstart
事件,拖拽进入dragenter
事件,拖拽离开dragleave
事件,拖拽经过dragover
事件,拖拽释放drop事件以及拖拽结束dragend
事件
# 属性和方法
DataTransfer对象包含下面5个标准属性和4个标准方法
标准属性
- DataTransfer.dropEffect 获取当前所选拖放操作的类型,或将拖拽操作设置为新类型。值必须为none,copy,link或move中的一个。
- DataTransfer.effectAllowed 提供可能的所有类型的操作。必须是none,copy,copyLink,copyMove,link,linkMove,move,all或uninitialized中的一个。
- DataTransfer.files 拖拽的本地文件列表。如果拖动操作不涉及拖动文件,则此属性为空列表。
- DataTransfer.items (只读) 提供DataTransferItemList对象,该对象是所有拖动数据的列表。
- DataTransfer.types (只读) 在dragstart事件中设置数据格式,返回的是一个字符串数组
标准方法
- DataTransfer.clearData([format]) 删除与给定类型关联的数据。format参数是可选的。如果类型为空或未指定,则删除所有关联的数据。如果指定类型的数据不存在,或者数据传输不包含任何数据,则此方法无效。
- DataTransfer.getData(format) 返回给定类型的数据,如果该类型的数据不存在或数据传输不包含数据,则返回空字符串。
- DataTransfer.setData(format, data) 设置给定类型的数据。如果该类型的数据不存在,则在末尾添加,以使列表中的最后一项成为新格式类型。如果该类型的数据已存在,则在相同位置把现有数据替换掉。
- DataTransfer.setDragImage(img, xOffset, yOffset) 设置用于拖动的自定义图像。
# 详细介绍
# DataTransfer.dropEffect
dropEffect属性顾名思意拖拽效果
,在PC web端主要表现在鼠标手形上。不同的dropEffect值,鼠标的手形效果是不一样的
dropEffect值:
- move: 鼠标样式
- copy: 加号样式
- link: 链接样式
- none: 禁止样式 (实测chrome和move样式相同)
dropEffect 属性的设置主要用在目标元素
的dragenter和dragover事件中,同时受effectAllowed属性影响。
例如,我们在dragstart的时候设置effectAllowed属性值为'none',则dropEffect只能表现为'none',而不会出现其他手形,即使设置了其他手形对应的属性值
# DataTransfer.effectAllowed
表示拖拽允许的效果
effectAllowed值:
- uninitialized:默认值,表示未初始化。从效果上来讲,和all是一样
- none:不允许拖拽。鼠标保持禁止状态
- copy:可以在新位置复制元素
- copyLink:允许复制和链接操作
- copyMove:允许复制和移动操作
- link:可以在新位置建立链接
- linkMove:允许链接和移动操作
- move:可以把元素移动到新位置
- all:什么操作都允许
如果effectAllowed属性值设置为上面列表以外的其它值则没有任何效果。另外在IE浏览器下所有的字都会小写,因此类似linkMove会变成linkmove
# effectAllowed和dropEffect的关系
effectAllowed和dropEffect通常应用的事件方法名不一样,effectAllowed多用在dragstart事件中,而dropEffect属性的设置主要用在dragenter和dragover事件中。
effectAllowed和dropEffect的彼此间是有制约关系,当我们给effectAllowed设置了对应的属性值,则dropEffect只能设置为effectAllowed允许的值,否则是无效的。
举个例子,如果我们设置effectAllowed值为'copyMove',则dropEffect只有'copy'和'move'这两个属性值才有效。
effectAllowed看上去很屌,但实际应用的时候相当鸡肋。我们通常的拖拽应用是用不到这个的。只要下面这个场景,那就是当我们有很多个元素需要拖拽,但是需要像垃圾一样分门别类的时候,effectAllowed就有用了。
原生拖拽事件有这样一种行为,那就是如果effectAllowed值和dropEffect值不一致,则无法响应drop事件。我们可以想象一下,假设我们在网页中放三个垃圾箱,分别回收move元素,copy元素和link元素,由于DOM元素的转移或者复制我们都是在drop事件中完成的,则effectAllowed包含copy元素的才能拖拽进入copy垃圾箱(可以触发drop事件)。
平常开发都是简单的拖拽,哪里需要用到分门别类啊,因此effectAllowed也就无用武之地了
实例:https://codepen.io/SitePoint/pen/epQPNP
# DataTransfer.Files
当我们从桌面往网页浏览器中拖文件的时候,DataTransfer.files就派上用场了,其对应的列表只就是我们拖进去的文件列表
function OnDragDrop(event) {
const files = event.dataTransfer.files || [];
console.log(files);
//阻止浏览器默认打开
event.preventDefault();
}
File 对象
{
lastModified: 1515742342000
lastModifiedDate: Fri Jan 12 2018 15:32:22 GMT+0800 (China Standard Time)
name: "avatar.jpg"
size: 83203
type: "image/jpeg"
webkitRelativePath: ""
}
# DataTransfer.items
DataTransfer.items可以用来获取拖拽的数据信息,只读。
DataTransfer.items 为 DataTransferItem 类型的数据列表集合,而DataTransferItem又包含多个属性和方法,属性包括kind
和type
,方法包括getAsString()
和getAsFile()
,这个和剪切板item对象方法是一致的。
function OnDragDrop(event) {
const items = event.dataTransfer.items || [];
console.log(items);
console.log(items);
console.log(items[0]?.kind); //file
console.log(items[0]?.type); //image/jpeg
console.log(
items[0].getAsString(function (str) {
console.log("\ngetAsString: " + str);
})
); //undefined
console.log(
items[0].getAsFile(function (str) {
console.log("\ngetAsString: " + str);
})
); //File
//阻止浏览器默认打开
event.preventDefault();
}
File 对象
{
lastModified: 1515742342000
lastModifiedDate: Fri Jan 12 2018 15:32:22 GMT+0800 (China Standard Time)
name: "avatar.jpg"
size: 83203
type: "image/jpeg"
webkitRelativePath: ""
}
通用处理函数
document.addEventListener('drop', function (event) {
var items = event.dataTransfer.items || [];
handleDataTransferItems(items);
});
handleDataTransferItems = function (items) {
for (var i = 0; i < items.length; i += 1) {
var kind = items[i].kind;
var type = items[i].type;
// 逻辑开始
if (kind == 'string') {
if (type.indexOf('text/plain') != -1) {
items[i].getAsString(function (str) {
// str是纯文本,该怎么处理,就在这里处理
});
} else if (type.indexOf('text/html') != -1) {
items[i].getAsString(function (str) {
// str是富文本,就在这里处理
});
} else if (type.indexOf('text/uri-list') != -1) {
items[i].getAsString(function (str) {
// str是uri地址,在这里进行处理
});
}
} else if (kind == 'file') {
// 如果是图片
if (type.indexOf('image/') != -1) {
var file = items[i].getAsFile();
// file就是图片文件对象,可以上传,或者其他处理
}
}
}
};
# DataTransfer.types
DataTransfer.types用在dragstart
事件中,包含拖拽内容的包含的mimeType类型们,可以遍历出具体的type类型
document.addEventListener('dragstart', function (event) {
// 遍历并输出拖拽内容的类型
var types = event.dataTransfer.types || [];
[].slice.call(types).forEach(function (type) {
console.log(type);
});
});
DataTransfer.types有什么用呢?如果我们希望页面某些元素可以拖拽,有些不允许,则可以使用types属性进行检测,例如,如果是包含Files,则执行event.preventDefault(),拖拽行为就会被禁止。
# DataTransfer.getData()
DataTransfer.getData(format)可以快捷获取拖拽的内容
format可以理解为就是DataTransfer.items中的type值,例如,我们想要获取拖拽内容的富文本格式
document.addEventListener('drop', function (event) {
// 获取拖拽富文本内容
var html = event.dataTransfer.getData('text/html');
});
如果是获取纯文本,可以text/plain,或者有时候text/uri-list,实际开发时候,我们会直接使用'text'
document.addEventListener('drop', function (event) {
// 获取拖拽纯文本内容
var html = event.dataTransfer.getData('text');
});
Note: 如果采用原生的获取方式,如上述默认的获取text
,会出现获取不到的情况,所以,一般情况是和DataTransfer.setData()
配合使用的,先setData(),后getData()
# DataTransfer.setData()
DataTransfer.setData(format, data)可以自定义拖拽的内容信息。可以重置原生的拖拽内容,或者用来参数传递
我们实际开发基本上都是拖拽具体模块元素,此时setData()方法多用来传递拖拽元素的id
# DataTransfer.clearData()
DataTransfer.clearData()只能用在dragstart事件中,会清除所有的数据。也就是执行了此方法后,DataTransfer.getData()方法只能获得空字符串。
当我们需要使用setData()方法自定义拖拽数据的时候,为了避免原生拖拽数据干扰,可以先执行一次clearData()方法。这样可以避免text/html类型数据干扰(如果我们自定义的是纯文本数据)
# DataTransfer.setDragImage()
DataTransfer.setDragImage(img, offsetX, offsetY)用在dragstart事件中,可以设置拖拽时候有个图片跟在后面。其中,img表示图片DOM元素对象,offsetX表示距离鼠标的水平偏移距离,offsetY表示距离鼠标的垂直偏移距离。
var image = new Image();
image.src = './1f603.svg';
document.addEventListener('dragstart', function (event) {
// 设置拖拽图片
event.dataTransfer.setDragImage(image, 10, 10);
});