我在 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` 事件在 `draggable` 元素上触发 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
属性可以是:move
:拖动的数据将被移动到放置区。copy
:拖动的数据将被复制到放置区。- ..
放置区
要使元素成为放置区,它必须同时具有 dragover 和 drop 事件处理程序。
记得在
dragover
处理程序中调用 e.preventDefault(),否则浏览器不会让你在里面放置任何东西
dropzone.addEventListener('dragover', function handleDragOver(e) { // `dropzone` 元素必须同时具有 `dragover` 和 `drop` 事件 // 记得阻止浏览器的默认行为,否则它不会让你在里面放置任何东西 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()` // 在处理 dragover 或 dragenter 时,`getData()` 将返回空字符串 })
- 请记住,我们只能在
drop-handler
中使用dataTransfer.getData()
(在 dragover 或 dragenter 处理程序中它将返回空字符串)
dragend
- 无论拖动操作是完成还是被取消,dragend 事件都会在拖动操作结束后触发
// `dragend` 事件在 `draggable` 元素上触发(不是在放置区元素上) dragElem.addEventListener('dragend', function handleDragEnd(e) { // 我们可以通过检查 `e.dataTransfer.dropEffect` 值来确定拖动是否成功 let dropEffect = e.dataTransfer.dropEffect // 如果失败,`e.dataTransfer.dropEffect` 的值将是 "none" })
- 如果拖动操作失败,
e.dataTransfer.dropEffect
的值将是"none"
参考资料
← Previous postJavaScript 中 Array.prototype.map 的棘手用例
Next post →使用 git 时的关键笔记