# 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又包含多个属性和方法,属性包括kindtype,方法包括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);
});
陕ICP备20004732号-3