Sortable.js 拖拽后顺序变了但数据没更新怎么办?

程序员怡萱 阅读 45

我用 Sortable.js 做了一个列表拖拽排序,视觉上元素位置确实变了,但我发现背后的数组数据根本没跟着变。我试过在 onEnd 回调里手动 splice 更新数组,但索引总是对不上,拖两下就乱了。

这是我的初始化代码:

new Sortable(document.getElementById('list'), {
  onEnd: function (evt) {
    const oldIndex = evt.oldIndex;
    const newIndex = evt.newIndex;
    // 我在这里操作 this.myArray,但结果不对
  }
});

是不是我取索引的方式有问题?或者应该用别的方法同步数据?

我来解答 赞 4 收藏
二维码
手机扫码查看
1 条解答
Tr° 毓君
问题在于你直接用 splice 移动元素时没有考虑索引变化。当你从旧位置移除元素后,如果新位置在旧位置后面,数组实际长度变了,newIndex 对应的位置就错了一位。

正确做法是判断一下索引关系:

new Sortable(document.getElementById('list'), {
onEnd: function (evt) {
const { oldIndex, newIndex } = evt;
const item = this.myArray.splice(oldIndex, 1)[0];
// 如果向后移动,插入位置要减1
const insertIndex = newIndex > oldIndex ? newIndex - 1 : newIndex;
this.myArray.splice(insertIndex, 0, item);
}
});
或者更省事的方法是用 move 方法,Sortable.js 官方推荐用这个,帮你处理了各种边界情况:

<pre class="pure-highlightjs line-numbers"><code class="language-javascript">new Sortable(document.getElementById('list'), {
animation: 150,
handle: '.handle', // 你的拖拽手柄选择器
onEnd: function (evt) {
// 直接帮你排好序了
this.myArray.splice(evt.newIndex, 0, this.myArray.splice(evt.oldIndex, 1)[0]);
}
});


还有个小提示:如果你的列表项有唯一 ID,建议用 toArray + get 方法,这样更稳,不依赖 DOM 索引:

// 获取排序后的id数组
const orderedIds = sortable.toArray();

// 根据新顺序重排你的数据
this.myArray.sort((a, b) => orderedIds.indexOf(a.id) - orderedIds.indexOf(b.id));
```

索引问题排查的时候可以在回调里先 console.log 一下 oldIndex 和 newIndex,看看实际值是多少,心里就有数了。
点赞
2026-03-12 10:01