vuedragable使用:list,而不是Vue3组合API的v-model



我有这个使用组合API的Vue3组件:

<script setup lang="ts">
import { reactive } from "vue";
import draggable from "vuedraggable"
const myArray = reactive([
{ name : "AAA", id : 1},
{ name : "BBB", id : 2},
{ name : "CCC", id : 3},
{ name : "DDD", id : 4}
])
</script>
<template>
<draggable
:list="myArray"
@end="endDrag"
item-key="id">
<template #item="{element}">
<div>{{element.name}}</div>
</template>
</draggable>
</template>

这是有效的,在endDrag例程中,我看到myArray被重新排列。但是,如果我将:list更改为v-model,则屏幕上的列表不会更改,并且拖动的元素会返回到其原始位置。并不是说myArray没有改变。

Bug或功能?我做错什么了?谢谢你的启发!

我刚刚遇到了同样的问题。让我和大家分享我的理解。

首先,让我们确定一些事实。

众所周知,v-model基本上是这样的:

<Component :modelValue="myObject" @update:modelValue="(newObject) => myObject = newObject/>

如果使用脚本设置,则声明的const和其他声明将成为对象的属性。

所以这个:

const myObject = reactive({
id: 'App',
});

变成这样:

export default {
setup() {
const myObject = reactive({
id: 'App',
});
return {
myObject,
};
},
}

现在让我们把这些知识放在一起。当子组件发出带有新对象的事件update:modelValue时,Vue所做的是对安装程序返回的对象进行赋值。伪码中:setupObject.myObject = newObjectFromEvent

你可以通过这个简单的代码来证明这一点:

<script>
import { isProxy, reactive } from 'vue';
import Test from './Test';
export default {
components: {
Test
},
setup() {
const myObject = reactive({
id: 'App',
});
const setupObject = {
myObject,
};
setTimeout(() => {
console.log(setupObject.myObject);
console.log(isProxy(setupObject.myObject));
}, 5000);
return setupObject;
},
}
</script>
<template>
<Test v-model="myObject"/>
</template>

<script setup>
import { defineProps, isRef, watch } from 'vue';
const props = defineProps(['modelValue']);
watch(props.modelValue, () => {
console.log('Value changed!');
});
</script>
<template>
<button @click="$emit('update:modelValue', { id: 'Test' })">Click me</button>
</template>

点击按钮后,您会看到我们的console.log将输出:{id: 'Test'}false

此外,测试组件的观察程序也不会被触发,因为我们的属性不再是被动的,并且我们的测试组件仍然持有myObject的旧值

同样的事情也发生在可拖动的v型上。拖放项目时,属性(在您的情况下为myArray(将被可拖动组件发出的非反应对象覆盖,该属性将成为完成设置代码时创建的较大对象的一部分,因此您不会看到项目位置发生更改。

你可能会问,为什么它能和裁判一起工作?好吧,回到我们的@update:modelValue="(newObject) => myObject = newObject,如果你使用ref,Proxy不会消失,因为赋值是对myObject.value属性完成的。因此,当你使用ref时,它已经开始工作了。

使用reactive的另一种方法是手动处理更新:

const handleUpdate = (newObject) => {
Object.assign(myObject, newObject);
};
<Test :modelValue="myObject" @update:modelValue="handleUpdate"/>

这样你就不会失去反应性,因为你保留了相同的代理,只是重新分配了属性。

底线是,在使用具有反应对象或数组的v-model时,必须非常谨慎。

相关内容

  • 没有找到相关文章

最新更新