draggable="true"仅是拖拽起点标记,不配事件监听、不调setdata()、不在dragover中preventdefault(),拖拽必然失败;必须显式绑定dragstart、设置数据、阻止默认行为且目标需持续拦截dragover。

draggable="true"只是个开关,不配事件、不传数据、不阻止默认行为,拖拽必然失败。
dragstart 为什么没触发?
光标变手形 ≠ dragstart 被调用。浏览器不会自动绑定事件,必须显式注册。
-
draggable="true"必须写在被拖元素上(比如<div draggable="true">),<code><input>或<textarea></textarea>加了也无效 - 必须用
addEventListener('dragstart', ...)或内联ondragstart;只设属性不写监听,事件根本不会来 -
event.dataTransfer.setData('text/plain', 'some-id')必须在dragstart回调里执行;类型建议用'text/plain'或'text/html'—— 自定义类型如'mydata'在 Firefox 中会静默失败 - 空
<div> 没宽高时,浏览器判定“不可交互”,<code>dragstart不触发;加min-height: 24px或padding: 4px就能解决 - 检查是否被样式拦住:
user-select: none或pointer-events: none会让mousedown都失效,dragstart更不可能触发 - 目标容器必须监听
dragover,且回调中必须调用e.preventDefault()——e.stopPropagation()、return false都不行 - 只监听
drop是无效的;浏览器在dragover阶段就决定是否允许投放,没preventDefault(),drop根本不会派发 - 目标容器若为空
<div>,确认它没被 <code>display: none或visibility: hidden隐藏,否则无法命中 - Safari 对
effectAllowed和dropEffect匹配更敏感:建议在dragstart里设e.dataTransfer.effectAllowed = 'move',在dragover里设e.dataTransfer.dropEffect = 'move' - 这不是兼容性问题,是平台级限制;别直接照搬桌面代码
- 需降级为
touchstart/touchmove/touchend+ CSStransform手动模拟 - 或引入轻量库如
interact.js或sortablejs,它们内部已做平台兼容处理 - 若坚持用原生 API,至少检测
'ontouchstart' in window并切换为点击+长按激活模式 - 别依赖
event.target做业务判断;用event.currentTarget才是你监听的容器 - 如果需要获取被拖元素 ID,应从
dataTransfer.getData('text/plain')拿,而不是靠 DOM 层级推断 - 如果要支持嵌套结构,drop 处理逻辑里最好用
closest('.drop-zone')向上找容器,而不是信任event.target
drop 为什么完全不执行?
90% 的原因是 dragover 没拦住浏览器默认拦截逻辑。它不是可选步骤,而是硬性前提。
移动端拖拽为什么失效?
iOS Safari 和 Android Chrome 均不触发 dragstart/drop 等事件。draggable="true" 在移动端基本是摆设。
drop 里 event.target 不是你绑事件的容器?
drop 事件中的 event.target 可能是子元素(比如你拖到一个带文字的 <div>,<code>target 反而是里面那个 <span></span>),不是你绑定事件的容器本身。
最常被忽略的是:dragover 不仅要存在,还必须每次触发都 preventDefault();哪怕只漏一次,整个 drop 流程就断了。这个细节在调试时很难定位,因为控制台不报错,只是“静默失败”。











