Sortable.js跨列表拖拽后数据不同步怎么办

❤宇轩 阅读 98

我在用Sortable.js实现两个列表之间的拖拽功能,拖过去后数据没变,控制台还报错Cannot set property ‘done’ of undefined,试过在onEnd里手动改数组也不行,求大佬看看哪里错了

代码结构是这样的:items: [{id:1,done:false},...], doneItems: [],初始化了两个sortable实例:


Sortable.create(leftList, {
  group: 'shared',
  onEnd: (e) => {
    if(e.to === rightList) {
      const item = this.items.splice(e.oldIndex, 1)[0];
      item.done = true;
      this.doneItems.push(item); // 这里报错
    }
  }
});

发现拖到doneItems列表后,数据数组里的对象居然变成了undefined,但DOM显示正常。用Vue开发,可能和响应式系统有关?

我来解答 赞 9 收藏
二维码
手机扫码查看
2 条解答
东方万华
你这个问题主要是因为 this.items.splice 拿到的数据不对导致的,this.items 是 Vue 的响应式数据,直接 splice 虽然能改数组,但如果你的 e.oldIndex 是基于 DOM 的索引,那不一定对应到 Vue 的数据索引,尤其是在拖拽跨列表时,状态同步容易出问题。

而且你在 onEnd 里面直接操作 this.itemsthis.doneItems 这两个响应式数据的时候,如果没处理好引用,很容易出现你看到的 undefined

报错那句是因为你取数据的时候已经出错了,this.items 可能已经是空的或者不对的,所以 splice 出来的数据是 undefined

---

**根本原因:**
e.oldIndex 是在 DOM 列表里的索引,不是你 Vue 数据里的索引,不能直接拿来用。

---

**解决办法:**

你应该通过拖拽的 DOM 元素找到对应数据的唯一标识(比如 id),再从 Vue 的数据中找到这个对象。

比如:

onEnd: (e) => {
if (e.to === rightList) {
const id = e.item.dataset.id; // 假设你在DOM上存了data-id
const item = this.items.find(i => i.id == id);
if (item) {
item.done = true;
this.items = this.items.filter(i => i.id != id);
this.doneItems.push(item);
}
}
}


同时,你在渲染
的时候也应该用 item.id,这样 Vue 才能正确追踪列表变化。

---

**更好的写法:**
把这种操作封装成一个方法,比如叫 moveItemToDone(id),这样逻辑更清晰,也方便测试和维护。

---

总结一下:
不要用索引直接操作数组,用唯一标识来操作数据,这样才能保证 Vue 的响应式机制能正常更新状态。你原来那个方式在纯 DOM 操作里没问题,但在 Vue 这种响应式框架里会翻车。
点赞 7
2026-02-05 02:01
程序员艳雯
问题出在 Vue 的响应式系统上,splicepush 都是能触发响应式的操作,但你的 this 指向不对。在 Sortable.js 的回调函数里,this 默认指向的是 Sortable 实例,而不是 Vue 组件实例。

性能上我们也不想频繁重新初始化 Sortable,所以直接改写成箭头函数来绑定正确的 this

Sortable.create(leftList, {
group: 'shared',
onEnd: (e) => { // 注意这里是箭头函数
if (e.to === rightList) {
const item = this.items.splice(e.oldIndex, 1)[0];
item.done = true;
this.doneItems.push(item);
}
}
});


另外,确保 rightList 是用 ref 或者 querySelector 正确获取到的 DOM 元素,别拿错变量了。如果还是报错,建议打印一下 this 看是不是 Vue 实例。

最后吐槽一句,Sortable.js 虽然好用,但和 Vue 响应式系统的兼容性确实有点坑,多留意回调里的上下文问题就对了。
点赞 2
2026-01-31 12:01