拖拽排序时列表项位置错乱怎么办?
我用原生 JS 实现了一个简单的拖拽排序功能,但松开鼠标后列表项的位置总是不对,有时候还会重复或者消失。明明拖动时视觉反馈是正常的,可一 drop 就乱了。
下面是我目前的 HTML 结构,每个 li 都加了 draggable=”true”,也监听了 dragstart、dragover 和 drop 事件,但数据更新和 DOM 顺序好像没对齐:
<ul id="sortable-list">
<li draggable="true">Item 1</li>
<li draggable="true">Item 2</li>
<li draggable="true">Item 3</li>
<li draggable="true">Item 4</li>
</ul>
drop事件里才去处理 DOM 交换,导致索引计算和实际状态对不上。按照 HTML5 拖拽规范的建议,应该在dragover事件中实时计算位置并移动 DOM,而不是等到松手。dragover事件在鼠标移动时会高频触发,正好用来做实时的位置预判和插入。核心思路是:获取鼠标当前 Y 坐标,计算它位于列表中哪个元素的上方或下方,然后利用
insertBefore实时调整 DOM 结构。这样当你松开鼠标(触发drop)时,DOM 顺序已经是正确的了,数据源只需要在dragend时根据 DOM 重新获取即可。下面是标准写法的完整代码,直接就能用:
另外,CSS 里记得加个样式给拖拽中的元素,比如
.dragging { opacity: 0.5; },不然视觉上可能看不出哪个在动。这种做法的好处是 DOM 操作和视觉反馈是同步的,不用去维护复杂的索引数组,最后直接读 DOM 就是最新的顺序,省心又不容易出 Bug。