如何使用拖拽式API(Drag and Drop API)

391 阅读4分钟

使用Drag and Drop API,你可以定义页面中哪些元素是可拖动的,并在用户拖动某个元素时进行拦截。

它在现代浏览器上得到了很好的支持。

Browser support

在我们开始研究API之前,我们必须知道如何定义页面中哪些元素是可拖动的。我们可以通过在页面HTML中添加draggable 属性来实现,其值为true

<div draggable="true">
  ...
</div>

这就足以使该元素可拖动。

提示:图像、文本选择和链接默认是可拖动的,除非你将draggable 设置为false。

我们还可以在浏览器中拖动用户电脑中的文件。在这种情况下,我们是在传输文件

我们可以将元素拖到哪里是我们需要澄清的另一点。除了我们不能随便拖动任何元素外,我们也不能随便拖入任何元素。该元素必须是有效的下降目标

要使一个元素成为下降目标,你要监听它的dragover 事件,你要么从它那里返回false,要么在传递的事件上调用preventDefault()

const element = document.querySelector('#my-drop-target)
element.addEventListener('dragover', event => {
  event.preventDefault()
})

一旦我们这样做,我们就有了一个可拖动的元素和一个投放目标,我们就可以开始了。我们可以与可拖动元素上的事件互动。

  • dragstart
  • drag
  • dragend

在下降目标上。

  • dragenter
  • dragover
  • dragleave
  • drop

拖放操作和触发的事件概述

当用户开始拖动一个可拖动的元素,用鼠标点击它并移动鼠标,或者轻拍并保持轻拍,然后移动选择,dragstart 事件被触发。

element.addEventListener('dragstart', event => {
  //...
})

作为参数传递给事件处理函数的event 对象是一个DragEvent 对象。

它从更一般的事件对象延伸出来,与所有其他事件共享:鼠标、键盘、滚动等。

此时,该元素正在被拖动,drag 事件被触发。在项目被拖动的过程中会有多次,所以我们必须像对scrollmouseover 事件那样使用节流。

一旦我们进入一个下降目标

  1. dragenter 事件在下降目标上被触发
  2. dragover 事件在下降目标上被触发。

如果一个被拖动的元素首先进入一个下降目标,然后远离它,dragleave 事件在下降目标上被触发。

如果用户释放鼠标,dragend 事件在被拖动的元素上被触发,而drop 事件在下降目标上被触发。

拖动数据。DataTransfer

正如我所提到的,每个与拖放有关的事件都是一个DragEvent 对象,它带有一个名为 dataTransfer的属性,它持有被拖动的数据,并提供5个属性。

  • dropEffect
  • effectAllowed
  • files
  • items (只读)
  • types (只读)

当拖动事件开始时,你可以做一些操作。

设置/获取效果

你可以通过在dragstart 事件中设置effectAllowed 属性来设置拖动操作的理想效果。你有几个选项,这些选项设置了投放目标应该如何处理投放的元素。

  • none 它不应该被丢弃
  • move 它可以被移动
  • copy 可以复制
  • link 可以被链接
  • copyMove 可以复制或移动
  • copyLink 它可以被复制或链接
  • linkMove 可以移动或链接
  • all 它可以被复制、移动或链接

(都是字符串)。

默认是all

dropEffect 属性用于获取拖放操作的类型,这次是由用户通过使用修改键来设置。例如,在Mac上按下Alt 键将拖放目标设置为复制项目而不是移动项目。

这个属性不是只读的。我们可以在dragenterdragover 事件中对其进行编辑,使其成为这些字符串值之一。

  • none 它不应该被丢弃
  • move 它可以被移动
  • copy 可以复制
  • link 可以被链接

例子。

element.addEventListener('dragenter', event => {
  event.dataTrasfer.dropEffect = 'move'
})

正在传输的数据

你可以从dataTransfer.items ,这是一个类似于数组的对象,你可以用一个循环来迭代,获得对每个 DataTransferItem对象。

DataTransferItem 有两个只读的属性。

  • kind:被拖动的项目的种类。返回一个字符串,包含filestring
  • type 项目的MIME类型

并且它有2个方法。

  • getAsFile() 返回一个代表被拖动的数据的 对象File
  • getAsString() 执行回调函数,输入一个代表被拖动数据的字符串对象。

它们有一个类似的名字,但工作方式非常不同。第一个方法返回一个File 对象。

element.addEventListener('dragenter', event => {
  for (item of event.dataTrasfer.items) {
    const theFile = item.getAsFile()
  }
})

flaviocopes.com/file/了解更多关于文件对象的信息

第二种将项目作为一个字符串传递给回调函数。

element.addEventListener('dragenter', event => {
  for (item of event.dataTrasfer.items) {
    item.getAsString(theString => {
      console.log(theString)
    })
  }
})

被拖动的项目文件的类型存储在dataTransfer 对象的types 属性中。它是一个数组,默认情况下包含字符串string 。如果我们正在拖动一个文件,相应的类型是一个字符串,值为Files

如果有文件被传输,除了被列在dataTransfer.items ,它们还被存储在dataTransferfiles 属性中。

这个属性指向一个列出被拖动的文件的FileList 对象。

请看Codepen上的这个演示。

看笔的 拖放!作者Flavio Copes(@flaviocopes)在CodePen上。