背景
在给拼图怪加画布内图片拖拽调换功能时,遇到了一个典型的”浏览器啥也不说就是不工作”的问题。
症状
- 图库拖到画布:✅ 正常
- 画布内拖拽互换:❌ 完全不触发 drop
- 控制台只有:
dragstart→dragend(中间没有dragover、没有drop)
根因
HTML5 Drag & Drop 规范有一条规则:
dragstart设置effectAllowed,dragover设置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 的调试要点:
drop不触发 → 先查effectAllowed和dropEffect是否兼容- 事件冒泡链上最后的
dropEffect是生效值 - DOM 替换在拖拽过程中会破坏浏览器拖拽状态
- 调试方法:
dragenter、dragover、dragleave、drop四个事件都加 console.log