原生HTML5拖拽排序需绑定dragover/drop到容器并用closest定位li、e.preventDefault()启用drop、getBoundingClientRect计算插入点、iOS降级处理、dataTransfer仅传ID。
原生 HTML5
拖拽排序
能跑通,但用户一上手就卡顿、插错位、iOS 上直接失灵——问题不在“会不会写”,而在事件绑定粒度、插入逻辑和平台边界没理清。
dragover 必须绑定到容器,不是每个
常见错误是给每个
单独绑
和
,结果事件频繁冒泡、判断错乱,光标悬停时列表项疯狂闪动。正确做法是只在容器(如
)上监听
和
,再用
定位当前悬停项。
里必须调用
,否则 Safari/Chrome 都会拒绝 drop
不要在
里做 DOM 修改(比如加 class),高频触发会导致重排;改用
节流或仅更新
属性
若列表项内有按钮、图标等子元素,
可能是它们,不一定是
,所以必须用
向上找
drop 时插入位置要靠
算,不能只看
靠
这类写法,只能实现“插到某项后面”,用户拖到两项中间时,实际插入点永远偏移——因为
不代表鼠标意图。真实体验需要根据鼠标 Y 坐标判断该插在哪个
之前还是之后。
在
中获取目标
的
,算出垂直中点:
对比
和
:小于则插在它前面,大于则插在它后面
插入前先
,避免 DOM 中残留副本
别忘了清理所有
的临时 class(如
),否则视觉残留
移动端 iOS Safari 不支持
,降级方案得提前写死
iOS 上
是被硬禁用的,事件根本不会触发,控制台也不报错——你调试半天发现连
都没进,就是这个原因。
使用HTML,CSS,JavaScript开发Android应用程序 英文文字pdf版附源文件
如果你了解HTML,CSS和JavaScript,您已经拥有所需的工具开发Android应用程序。本动手本书展示了如何使用这些开源web标准设计和建造,可适应任何Android设备的应用程序 - 无需使用Java。您将学习如何创建一个在您选择的平台的Android友好的网络应用程序,然后转换与自由PhoneGap框架到一个原生的Android应用程序。了解为什么设备无关的移动应用是未来的潮流,并开始构建应用程序,提供更
下载
立即学习
“
前端免费学习笔记(深入)
”;
检测是否为 iOS:
,成立就跳过原生拖拽初始化
降级用点击交互:每项加 ↑ ↓ 按钮,或长按弹出位置选择浮层(
对应真实数据索引)
如果项目已引入 SortableJS,直接启用
,它内部用
模拟,且处理了滚动冲突
切勿尝试自己用
手搓拖拽——缩放、惯性滚动、多指操作会让逻辑崩坏
dataTransfer 只传 ID,别传 HTML 或 JSON 字符串
看似方便,但一旦列表项含表单控件(
、
),值状态会丢失;传 JSON 更危险:跨 iframe 或 CSP 严格策略下可能被截断或拒绝。
只存标识:
DOM 插入后,立刻用该 ID 查找原始数据数组,同步更新 JS 状态(如
)
若需持久化,drop 后立即调用
或发 API,别等到页面卸载
避免在
里读取大量 DOM 内容,影响拖拽起始响应速度
最易被忽略的一点:拖拽过程中用户可能意外刷新页面,或切换标签页。如果业务强依赖顺序,得在
前就缓存一次当前顺序,否则 drop 前中断,数据就回不去了。
lilidragoverdropul#sortable-listdragoverdrope.target.closest('li')dragovere.preventDefault()dragoverrequestAnimationFramedata-drag-overe.targetliclosest('li')getBoundingClientRect()nextSiblinglist.insertBefore(draggedItem, target.nextSibling)nextSiblinglidragoverligetBoundingClientRect()const mid = (rect.top + rect.bottom) / 2e.clientYmidlist.removeChild(draggedItem)lidrag-overdraggabledraggable="true"dragstart/(iPad|iPhone|iPod)/.test(navigator.userAgent)data-idforceFallback: truetouchstart/move/endtouchmove + transforme.dataTransfer.setData('text/html', el.innerHTML)inputselecte.dataTransfer.setData('text/id', el.dataset.id)dataListlocalStorage.setItem()dragstartdragstart