Sortable.js跨列表拖拽后数据不同步怎么办
我在用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开发,可能和响应式系统有关?
this.items.splice拿到的数据不对导致的,this.items是 Vue 的响应式数据,直接splice虽然能改数组,但如果你的e.oldIndex是基于 DOM 的索引,那不一定对应到 Vue 的数据索引,尤其是在拖拽跨列表时,状态同步容易出问题。而且你在
onEnd里面直接操作this.items和this.doneItems这两个响应式数据的时候,如果没处理好引用,很容易出现你看到的undefined。报错那句是因为你取数据的时候已经出错了,
this.items可能已经是空的或者不对的,所以splice出来的数据是undefined。---
**根本原因:**
e.oldIndex是在 DOM 列表里的索引,不是你 Vue 数据里的索引,不能直接拿来用。---
**解决办法:**
你应该通过拖拽的 DOM 元素找到对应数据的唯一标识(比如 id),再从 Vue 的数据中找到这个对象。
比如:
同时,你在渲染
item.id,这样 Vue 才能正确追踪列表变化。---
**更好的写法:**
把这种操作封装成一个方法,比如叫
moveItemToDone(id),这样逻辑更清晰,也方便测试和维护。---
总结一下:
不要用索引直接操作数组,用唯一标识来操作数据,这样才能保证 Vue 的响应式机制能正常更新状态。你原来那个方式在纯 DOM 操作里没问题,但在 Vue 这种响应式框架里会翻车。
splice和push都是能触发响应式的操作,但你的this指向不对。在 Sortable.js 的回调函数里,this默认指向的是 Sortable 实例,而不是 Vue 组件实例。性能上我们也不想频繁重新初始化 Sortable,所以直接改写成箭头函数来绑定正确的
this:另外,确保
rightList是用ref或者querySelector正确获取到的 DOM 元素,别拿错变量了。如果还是报错,建议打印一下this看是不是 Vue 实例。最后吐槽一句,Sortable.js 虽然好用,但和 Vue 响应式系统的兼容性确实有点坑,多留意回调里的上下文问题就对了。