Vue Draggable 拖拽后数据顺序没更新是怎么回事?

___诗晴 阅读 30

我用 Vue Draggable 做了个列表拖拽排序,但拖完之后 data 里的数组顺序没变,明明绑定了 v-model 啊。

我试过用 :list.syncv-model 两种方式,都不行。控制台打印出来的还是原始顺序,但 UI 上看起来已经排好了。是不是漏了什么配置?

<draggable v-model="items" @end="onEnd">
  <div v-for="item in items" :key="item.id">{{ item.name }}</div>
</draggable>
我来解答 赞 2 收藏
二维码
手机扫码查看
1 条解答
打工人钰岩
别走弯路,这问题我踩过好几次,八成是数组里的元素不是响应式的,或者用了非响应式的方式改了数组。

先说最常见的情况:你数组里的每个 item 是对象,但可能在拖拽前后,Vue 没能检测到数组顺序的变化。Vue Draggable 是靠 v-model 双向绑定 list 的,但它底层是用 sort()、splice() 这些方法操作数组的,前提是你的数组本身要是响应式的。

最常见的坑是:
你可能在某个地方用了 Object.assignArray.prototype.concat、或者直接 items = [...items] 来“重置”数组,但没触发更新;或者更隐蔽的——你用 items.sort() 但没赋值回去(Vue2 里直接 sort 不会触发更新!)。

再看你的代码,绑定没问题,但得确认几个点:

第一,items 必须是 data 里声明过的,不能是 later 加上的;
第二,别在 onEnd 里手动操作 items,比如再做一次 sort 或 filter,否则会覆盖 Draggable 的结果;
第三,如果你用的是 Vue2,别忘了数组更新检测的限制——比如直接改索引 items[0] = newItem 是不行的,得用 this.$setsplice

最保险的做法是:
- 确保 items 是 data 里的数组
- 不要在 @end 里写任何对 items 的赋值或修改
- 确保每个 item 的 key 是唯一且稳定的(你用 id 是对的)
- 如果用 Vue2,升级到最新版的 vue.draggable.next(其实是 vuedraggable 这个包),别用老的 vue-draggable,坑巨多。

举个能跑的最小例子,你对比下:

<template>
<draggable v-model="items" @end="onEnd">
<div v-for="item in items" :key="item.id">
{{ item.name }}
</div>
</draggable>
</template>

<script>
import draggable from 'vuedraggable'

export default {
components: { draggable },
data() {
return {
items: [
{ id: 1, name: 'A' },
{ id: 2, name: 'B' },
{ id: 3, name: 'C' }
]
}
},
methods: {
onEnd(event) {
console.log(this.items) // 这里就能看到顺序变了
// 千万别再写 this.items = [...this.items] 之类的!
}
}
}
</script>


如果还是没更新,八成是你用了 :list.syncv-model 混着用,或者组件外面包了层 v-if 导致重新渲染。
实在不行,用 console.log(event.oldIndex, event.newIndex) 看拖拽事件,再手动用 splice 操作数组,但一般不用。
点赞
2026-02-24 11:02