拖拽 API 要点

A laptop computer sitting on top of a wooden desk
Published on
/5 mins read/---

我在 https://hta218.github.io/dnd-keynotes 创建了一个关于 Javascript 拖拽 API 的示例

以下是我学习这些 API 时总结的一些有趣要点。

基本概念

  • 典型的拖拽操作开始于用户选择一个可拖拽元素,将元素拖拽到放置区域,然后释放被拖拽的元素。

  • 事件:

事件触发时机…
drag…被拖拽项目(元素或文本选择)正在被拖拽时。
dragend…拖拽操作结束时(如释放鼠标按钮或按下 Esc 键)
dragenter…被拖拽项目进入有效放置目标时。
dragexit…某个元素不再是拖拽操作的直接选择目标时。
dragleave…被拖拽项目离开有效放置目标时。
dragover…被拖拽项目在有效放置目标上方拖拽时,每几百毫秒触发一次。
dragstart…用户开始拖拽项目时。
drop…项目被放置到有效放置目标上时。

要点

  • 要使元素可拖拽,添加 draggable="true" 属性

    <div draggable="true">这个元素是可拖拽的</div>
  • dragstart

    • dragstart 是在可拖拽元素上开始拖拽操作时触发的第一个事件

    • 使用 e.dataTransfer.setData() 方法设置任何拖拽数据,这些数据在拖拽操作期间保持有效

    // `dragstart` 事件在`可拖拽`元素上触发
    dragElem.addEventListener('dragstart', function (e) {
      // 我们可以使用 `e.dataTransfer.setData` 方法设置数据
      e.dataTransfer.setData('text/plain', e.target.id)
      // 使用 e.dataTransfer.setDragImage() 来改变拖拽图像
      // e.dataTransfer.setDragImage(img | element, xOffset, yOffset)
    })
    • 如果你不想要在拖拽过程中从拖拽目标生成的半透明图像,使用 e.dataTransfer.setDragImage() 来改变它
  • dropEffect 属性

    • dropEffect 属性用于控制在拖拽操作期间给用户的反馈
    dragElem.addEventListener('dragstart', function (e) {
      e.dataTransfer.setData('text/plain', e.target.id)
      // `move` 值在 Windows 上有效,在 macOS 上无效 - 这可能是浏览器和操作系统的问题
      e.dataTransfer.dropEffect = 'move' // 或者 "copy"
    })
    • dropEffect 属性可以是:

      1. move: 被拖拽数据将被移动到放置区域。
      2. copy: 被拖拽数据将被复制到放置区域。
      3. ..
  • 放置区域

    • 要使元素成为放置区域,它必须同时具有 dragoverdrop 事件处理器。

    • 记住在 dragover 处理器中调用 e.preventDefault(),否则浏览器不会让你在里面放置任何东西

    dropzone.addEventListener('dragover', function handleDragOver(e) {
      // `放置区域`元素必须同时有 `dragover` 和 `drop` 事件
      // 记住要 preventDefault 这个行为,否则浏览器不会让你在里面放置任何东西
      e.preventDefault()
      e.dataTransfer.dropEffect = 'move'
    })
    dropzone.addEventListener('drop', function handleDrop(e) {
      // 注意:必须有 dragover 处理器才能使用 drop 事件
      e.preventDefault()
      // 使用 `e.dataTransfer.getData` 方法获取拖拽数据并处理它们
      let data = e.dataTransfer.getData('text/plain')
      // 注意:我们只能在 `drop-handler` 中使用 `dataTransfer.getData()`
      // `getData()` 在 dragover 或 dragenter 处理器中会返回空字符串
    })
    • 请记住,我们只能drop-handler 中使用 dataTransfer.getData()(在 dragoverdragenter 处理器中它会返回空字符串)
  • dragend

    • dragend 事件在拖拽操作完成后触发,无论拖拽是完成还是被取消
    // `dragend` 事件在`可拖拽`元素上触发(不是在放置区域元素上)
    dragElem.addEventListener('dragend', function handleDragEnd(e) {
      // 我们可以通过检查 `e.dataTransfer.dropEffect` 值来检查拖拽是否成功
      let dropEffect = e.dataTransfer.dropEffect
      // 如果失败,`e.dataTransfer.dropEffect` 的值将是 "none"
    })
    • 如果拖拽操作失败,e.dataTransfer.dropEffect 的值将是 "none"

参考资料