必须显式设置 draggable="true",否则普通元素无法拖拽;drop 区域须监听 dragover 并调用 preventDefault();数据传递唯一可靠方式是 dataTransfer。

必须显式设置 draggable="true",否则普通元素(如 <div>、<code><span></span>)根本拖不动——这是最常被忽略的起点。
可拖拽元素必须带 draggable="true"
HTML5 默认只允许 <img alt="HTML中如何实现拖放功能的基本结构" > 和 <a></a> 标签原生拖拽;其他所有元素都需要手动加属性。不写这句,后续事件监听全白搭。
-
draggable是布尔属性,写成draggable="true"或仅draggable都行,但不能省略 - 动态插入的元素(比如用
insertAdjacentHTML添加的)也要同步加上该属性,否则 JS 绑定的dragstart不会触发 - 某些框架(如 Vue/React)中,属性可能被自动过滤,需确认渲染后 DOM 确实存在该属性
drop 区域必须拦截 dragover 并调用 preventDefault()
dragover 事件默认被浏览器阻止,不主动干预,drop 就永远不会触发——这不是 bug,是规范设计。
- 只监听
drop不够,必须同时监听dragover并在其中执行event.preventDefault() - 不能只靠 CSS 或 class 控制,JS 层面的
preventDefault()是硬性要求 - 如果目标区域是空
<div>,记得设宽高或 <code>min-height,否则它“不可见”,拖进去也没反应dataTransfer 是唯一可靠的数据传递通道
别试图在
dragstart里存全局变量或闭包引用,跨事件生命周期只有dataTransfer能稳定传值。立即学习“前端免费学习笔记(深入)”;
-
setData("text/plain", ...)最兼容,适合传 ID、文本等简单内容;结构化数据建议用"application/json" -
getData()必须和setData()的 MIME 类型完全一致,大小写敏感,"Text"≠"text/plain" - 不要依赖
e.target在drop里找源元素——拖拽过程中 DOM 可能已变化,应以getData()拿到的 ID 为准去查document.getElementById()
真正容易翻车的地方不在逻辑,而在两个细节:一是忘记给动态生成的元素补
draggable="true",二是把dragover当成可选事件跳过。只要这两个点卡死,整个拖放链就断在第一步。 -



















