Alfred-Skyblue / vue-draggable-plus

Universal Drag-and-Drop Component Supporting both Vue 3 and Vue 2
https://vue-draggable-plus.pages.dev/en/
MIT License
2.99k stars 129 forks source link

一个可能由defineModel引起 v-model 绑定在无变化的bug #179

Open LoYoi-i opened 1 month ago

LoYoi-i commented 1 month ago

a -> b -> c

a组件中: <my-but v-model="buts_data" @save="" /> v-model 绑定了数据

b组件中: const model = defineModel<any[]>({ required: true })

给c组件用 <VueDraggable v-else v-model="buts_data" @end="onEnd">

现在的问题是,拖拽正常但是 v-model="buts_data" 绑定值不变化

onEnd 事件的回调函数,结果是对的,所以我现在 const buts_data = reactive(model.value as any[]) function onEnd(e: any) { // console.log(buts_data,model.value); const oi = e.oldIndex const ni = e.newIndex if (oi === ni) return // 检查索引是否有效 if (oi >= 0 && ni >= 0 && oi < buts_data.length && ni < buts_data.length) { // 保存要移动的元素 const itemToMove = buts_data[oi] // 移除要移动的元素 buts_data.splice(oi, 1) // 在新的位置插入元素 buts_data.splice(ni, 0, itemToMove) } }

在事件结束后手动处理的

YongYingWu commented 1 week ago

这种第一个怀疑的就是reactive的响应式和组件对modelValue的处理,于是就去看了源码,发现他对于绑定的modelValue值,是直接改变整个值, 在componen.ts中,

const list = computed({
      get: () => props.modelValue,
      set: v => emit('update:modelValue', v)
    })

    const target = ref()
    const data = reactive(
      useDraggable((props.target || target) as string, list, options)
    )

可以看到他是使用computed属性去劫持modelValue,然后对list就行处理,再统一更新整个modelValue的值,而reactive在vue的文档也有如下介绍:“不能替换整个对象:由于 Vue 的响应式跟踪是通过属性访问实现的,因此我们必须始终保持对响应式对象的相同引用。这意味着我们不能轻易地“替换”响应式对象,因为这样的话与第一个引用的响应性连接将丢失”, 所以更推荐使用ref来处理响应式