← 返回文章列表

Vue 中用原生 div 实现拖拽传值

前端
  • # vue
  • # drag-and-drop
  • # html

在页面里做一个简单拖拽时,不一定一上来就需要引入拖拽库。原生的 div 就支持拖拽,只要给元素加上 draggable="true"

<template>
  <div draggable="true">
    可拖拽元素
  </div>
</template>

这样元素就可以被拖起来了。不过如果只是这样写,拖到另一个元素上松开时,浏览器默认行为可能不会按预期把它当成一个可放置区域。

让目标元素可以接收拖拽

目标元素需要处理 dragover 事件,并阻止默认行为。在 Vue 里可以直接写成:

<template>
  <div @dragover.prevent>
    拖到这里
  </div>
</template>

这一步的作用是告诉浏览器:这个元素允许被拖拽内容放置。否则即使拖到了目标元素上,松开时也可能表现为不接收拖拽。

拖拽时传值

如果拖拽过程中需要把一些数据带到目标元素,可以在拖拽开始时通过 dataTransfer 写入数据。

<template>
  <div
    draggable="true"
    @dragstart="handleDragStart"
  >
    可拖拽元素
  </div>
</template>
const handleDragStart = (e: DragEvent) => {
  e.dataTransfer?.setData('schema', JSON.stringify({ a: '123' }))
}

这里的 'schema' 是自定义的数据类型名称,后面接收时用同一个名称取出来即可。

在目标元素接收值

目标元素监听 drop 事件,在松开时读取前面写入的数据。

<template>
  <div
    @dragover.prevent
    @drop="handleDrop"
  >
    拖到这里
  </div>
</template>
const handleDrop = (e: DragEvent) => {
  e.preventDefault()

  const raw = e.dataTransfer?.getData('schema')
  if (!raw) return

  const data = JSON.parse(raw)
  console.log(data)
}

完整的流程就是:

  1. 拖拽元素加上 draggable="true"
  2. dragstart 里用 dataTransfer.setData() 写入数据。
  3. 目标元素使用 @dragover.prevent 允许放置。
  4. drop 里用 dataTransfer.getData() 取回数据。

这样就可以用浏览器原生能力完成一个简单的拖拽传值。