334 字
2 分钟
HTML5 Drag & Drop 踩坑记录

背景#

在给拼图怪加画布内图片拖拽调换功能时,遇到了一个典型的”浏览器啥也不说就是不工作”的问题。

症状#

  • 图库拖到画布:正常
  • 画布内拖拽互换:完全不触发 drop
  • 控制台只有:dragstartdragend(中间没有 dragover、没有 drop

根因#

HTML5 Drag & Drop 规范有一条规则:

dragstart 设置 effectAlloweddragover 设置 dropEffect。浏览器在触发 drop 之前会检查两者是否兼容。不兼容就直接丢弃 drop,没有任何错误提示。

检查代码发现:

cell dragstart: effectAllowed = 'move'
wrap dragover: dropEffect = 'copy' ← 硬编码
cvs dragover: dropEffect = 'copy' ← 也是硬编码
→ 浏览器:'move' vs 'copy' 不兼容 → 拒绝 drop

修复#

// 所有 dragover handler 改为动态匹配
e.dataTransfer.dropEffect = e.dataTransfer.effectAllowed === 'move' ? 'move' : 'copy';

次要问题#

还有第二个坑:reorderPhotos() 直接调用 render() 替换 canvas.innerHTML,DOM 元素在拖拽过程中被替换了,浏览器的拖拽状态也被重置了。

修复方案:用 pendingReorder 标记,延迟到 dragend 才调 render()

教训#

HTML5 Drag & Drop 的调试要点:

  1. drop 不触发 → 先查 effectAlloweddropEffect 是否兼容
  2. 事件冒泡链上最后的 dropEffect 是生效值
  3. DOM 替换在拖拽过程中会破坏浏览器拖拽状态
  4. 调试方法:dragenterdragoverdragleavedrop 四个事件都加 console.log
HTML5 Drag & Drop 踩坑记录
https://blog.pangzee.cc.cd/posts/html5-drag-drop-pitfalls/
作者
SORA
发布于
2026-05-15
许可协议
CC BY-NC-SA 4.0