Vue Draggable 拖拽后数据顺序没更新是怎么回事?
我用 Vue Draggable 做了个列表拖拽排序,但拖完之后 data 里的数组顺序没变,明明绑定了 v-model 啊。
我试过用 :list.sync 和 v-model 两种方式,都不行。控制台打印出来的还是原始顺序,但 UI 上看起来已经排好了。是不是漏了什么配置?
<draggable v-model="items" @end="onEnd">
<div v-for="item in items" :key="item.id">{{ item.name }}</div>
</draggable>
先说最常见的情况:你数组里的每个 item 是对象,但可能在拖拽前后,Vue 没能检测到数组顺序的变化。Vue Draggable 是靠 v-model 双向绑定 list 的,但它底层是用 sort()、splice() 这些方法操作数组的,前提是你的数组本身要是响应式的。
最常见的坑是:
你可能在某个地方用了
Object.assign、Array.prototype.concat、或者直接items = [...items]来“重置”数组,但没触发更新;或者更隐蔽的——你用items.sort()但没赋值回去(Vue2 里直接 sort 不会触发更新!)。再看你的代码,绑定没问题,但得确认几个点:
第一,items 必须是 data 里声明过的,不能是 later 加上的;
第二,别在 onEnd 里手动操作 items,比如再做一次 sort 或 filter,否则会覆盖 Draggable 的结果;
第三,如果你用的是 Vue2,别忘了数组更新检测的限制——比如直接改索引
items[0] = newItem是不行的,得用this.$set或splice。最保险的做法是:
- 确保 items 是 data 里的数组
- 不要在 @end 里写任何对 items 的赋值或修改
- 确保每个 item 的 key 是唯一且稳定的(你用 id 是对的)
- 如果用 Vue2,升级到最新版的 vue.draggable.next(其实是
vuedraggable这个包),别用老的vue-draggable,坑巨多。举个能跑的最小例子,你对比下:
如果还是没更新,八成是你用了
:list.sync和v-model混着用,或者组件外面包了层v-if导致重新渲染。实在不行,用
console.log(event.oldIndex, event.newIndex)看拖拽事件,再手动用splice操作数组,但一般不用。