设 draggable="true" 却拖不动,是因为 dragstart 中未调用 setdata() 设置有效载荷;drop 不触发多因 dragover 未正确 preventdefault();移动端需降级处理,原生 draggable 基本不可用。

设了 draggable="true" 却拖不动,不是属性没生效,是拖拽链在 dragstart 就断了——浏览器只认“有数据可拖”,不认“你看起来像能拖”。
dragstart 里必须调 setData(),否则整个流程静默失败
很多代码只加了属性、绑了事件,但 dragstart 回调里空着,或只写了 e.dataTransfer.effectAllowed = 'move'。这不够。浏览器会认为“无有效载荷”,直接跳过后续所有事件。
-
setData()必须传非空字符串,推荐用text/plain类型,兼容性最稳;text/html在旧 Edge 和部分安卓 WebView 里静默失败 - 传 ID 比传索引可靠:列表重排后索引会变,
data-id不会;别传对象或 DOM 节点,setData()只接受字符串 - 动态渲染(如 React/Vue)时,避免重复绑定;用事件委托监听容器,再用
e.target.matches("[draggable='true']")过滤目标
drop 事件不触发?大概率是 dragover.preventDefault() 漏了或位置错了
drop 默认被浏览器拦截成“下载”或“跳转”,不手动拦,它连执行机会都没有。很多人只在 dragover 里写了 preventDefault(),却忘了——两个事件独立,缺一不可。
-
dragover和drop必须监听在同一个容器上(通常是ul或.column),不能一个绑在li、一个绑在ul -
preventDefault()必须出现在dragover回调第一句,不能放在条件分支里,也不能只写空函数 - 空容器会塌陷,拖进去没响应:给目标容器加
min-height: 1px或伪元素撑开高度
插入位置算不准?别依赖 clientY,用 DOM 结构定位更稳
用鼠标坐标算插入索引,在 Flex 布局、滚动容器、卡片高度不一时极易失真。坐标系偏移、缩放、iframe 嵌套都会让 clientY 失效。
- 跨列拖放时,优先用
Array.from(column.children).indexOf(event.target)获取索引 - 如果
event.target === column(拖到空白处),插入末尾,索引取column.children.length - 插入前必须检查
dragged === targetLi,否则insertBefore(dragged, dragged)会抛 DOM 异常 - 判断上下半区要算中线:
(rect.top + rect.bottom) / 2,只比rect.top容易误判
移动端原生 draggable 基本不可用,别硬扛
iOS Safari 和 Android Chrome 都不触发 dragstart/drop,这不是兼容性问题,是平台级缺失。你在 DevTools 里看到的“能拖”,真机上连事件监听器都不会进。
- 检测
'ontouchstart' in window后必须降级,不能靠draggable="true"硬扛 - 手动模拟时,
touchmove必须节流 +requestAnimationFrame,否则高频触发直接掉帧 - 如果允许引入轻量库,
interact.js或SortableJS已做平台适配,比自己填坑快得多
真正难的不是监听几个事件,而是松手那一帧,DOM 移动、数据索引、视觉反馈三者必须原子性对齐——稍有错位,用户就感觉“卡了一下”或“插错了位置”。这个时间窗口只有几毫秒,靠防抖、节流和结构化定位才能守住。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











