必须在dragstart事件中同步调用setdata(),否则drop事件不会触发;目标元素需在dragover中preventdefault();跨iframe拖拽datatransfer为空属安全限制。

必须在 dragstart 事件里调用 setData(),否则拖拽到目标上松手时 drop 根本不会触发——不是“放不进去”,是整个投放链路被浏览器静默中断。
draggable="true" 只是开门,不 setData 就等于没带钥匙
给 <div draggable="true"> 加了属性,只是让浏览器允许你“抓起”它;但拖拽协议要求必须提供可传输的数据,否则视为无效拖拽。浏览器会直接丢弃这次操作,<code>drop 事件永远不会到达目标元素。
-
dragstart中必须同步调用event.dataTransfer.setData("text/plain", "some-id"),不能延迟(比如放在setTimeout或 Promise.then 里) - 如果传的是对象或数组,先用
JSON.stringify()转成字符串,setData("application/json", JSON.stringify(obj)) - 避免只传空字符串或
undefined:setData("text/plain", "")在某些浏览器中仍可能阻断drop - 推荐固定使用
"text/plain"类型,兼容性最稳;自定义类型如"application/json"需确保drop侧用完全相同的字符串读取
drop 事件拿不到数据?先检查 dragover 是否 preventDefault
drop 不触发,90% 是因为目标区域没处理 dragover。这个事件的默认行为是禁止投放,必须显式阻止,否则浏览器连 drop 的机会都不给。
- 目标元素上必须监听
dragover并立即调用event.preventDefault() - 仅
drop里调preventDefault()没用——drop压根不会触发 - 可以顺便设置
event.dataTransfer.dropEffect = "move"来改变光标样式,但不影响数据读取 - 如果目标是
<input type="file">或原生文件区,规则不同,这里不适用
跨 iframe 拖拽时 dataTransfer 总是空?那是设计如此
浏览器出于安全限制,跨 iframe(甚至跨子域)拖拽时,dataTransfer 对象会被清空,getData() 返回空字符串。这不是 bug,是规范行为。
- 不要尝试绕过:无法通过
setData传递数据到另一个 iframe - 替代方案是用
window.postMessage()在拖拽开始前或drop后主动通信 - 可在
dragstart中记录源元素 ID,drop后通过 postMessage 发送该 ID 给目标 iframe,再由目标端查 DOM 或状态树 - 注意监听
message事件并校验event.origin,防止 XSS
最容易被忽略的点:拖拽源元素必须有明确的交互反馈(比如 cursor: move、:active 样式),否则用户根本不知道它能拖;而开发者常把问题归咎于 JS 逻辑,其实只是视觉线索缺失导致误判“没反应”。











