draggable="true"仅启用拖拽触发,需手动实现dragstart(必设datatransfer)、dragover(必preventdefault)和drop事件,且移动端不支持,须降级处理。

原生 draggable 属性只控制“是否可被拖拽”,不提供拖拽逻辑,开启后必须配合 dragstart/dragover/drop 等事件手动实现交互,否则拖不动、放不下、没反馈。
为什么设置了 draggable="true 却拖不动?
浏览器默认只允许图片、链接、选中文本被拖拽;其他元素即使加了 draggable="true",也因缺少 dragstart 事件中调用 event.dataTransfer.setData() 而被拦截。
- 必须在
dragstart事件里至少设置一个dataTransfer数据项,例如:event.dataTransfer.setData('text/plain', '') - 目标容器若要接收拖入,需阻止
dragover的默认行为(否则drop事件根本不会触发) -
draggable="true"只影响鼠标行为,不影响键盘焦点或可访问性,别误以为它等价于“可交互控件”
dragover 和 drop 事件必须成对处理
只监听 drop 是无效的——浏览器在 dragover 阶段就决定是否允许投放。常见错误是漏掉 dragover 或只写空回调。
- 在目标区域上绑定
dragover,并立即调用event.preventDefault()(这是关键!) - 可选地在
dragover中设置event.dataTransfer.dropEffect = 'move'控制光标样式 -
drop事件中通过event.dataTransfer.getData('text/plain')获取传入数据,注意类型需与setData时一致 - 不要依赖
event.target在drop中定位容器,它可能是子元素;建议用event.currentTarget或提前绑定到父容器
移动端没有原生 draggable 支持,别直接照搬
iOS Safari 和 Android Chrome 均不触发 dragstart/drop 等事件,draggable="true" 在移动端基本失效。
- 需要拖拽交互的场景,应改用
touchstart/touchmove/touchend+ CSStransform手动模拟 - 或者引入轻量库如
interact.js或sortablejs,它们内部已做平台兼容处理 - 若坚持用原生 API,至少检测
'ontouchstart' in window并降级为点击+长按激活模式
真正麻烦的不是写几行事件监听,而是跨浏览器拖拽状态同步、释放位置计算精度、与滚动容器协同、以及无障碍支持(比如键盘用户如何“拖拽”)。这些细节往往在第一次上线后才暴露出来。










