简体   繁体   English

为什么 vue v-model 不适用于数组道具?

[英]Why is vue v-model not working for an array prop?

I have a custom component that takes the modelValue prop and emits the update:modelValue event.我有一个自定义组件,它采用modelValue道具并发出update:modelValue事件。 In the parent component I pass an array:在父组件中,我传递了一个数组:

TestComponent.vue测试组件.vue

<template>
  <div>
     <button @click="updateIt">Test</button>
  </div>
</template>

<script>
export default {
    props: {
       modelValue: Array
    },
    emits: ["update:modelValue"],
    setup(props, {emit}){
        return {
            updateIt(){
                emit("update:modelValue", [4,5,6])
            }
        }
    }
}
</script>

App.vue应用程序.vue

<template>
  <div>
     <test-component v-model="myArr"/>
     <ul>
         <li v-for="i in myArr" v-text="i"></li>
     </ul>
  </div>
</template>

<script>
import TestComponent from "./TestComponent.vue";

export default {
    components: {
        TestComponent
    },
    setup(props, {emit}){
        const myArr = reactive([1,2,3]);

        return {
            myArr
        }
    }
}
</script>

The list will not get updated when I press the button, why?当我按下按钮时,列表不会更新,为什么?

Internally, the v-model directive gets changed to a handler function for the update:modelValue event that looks something like this:在内部, v-model指令更改为处理程序 function 用于update:modelValue事件,如下所示:

$event => ((exp => $event) where exp is the expression in the directive $event => ((exp => $event)其中 exp 是指令中的表达式

which basically means, when the update:modelValue event is emitted, the value you emit is assigned directly to the myArr variable, effectively replacing the whole reactive variable without triggering the reactivity chain, because it does not happen through the proxy.这基本上意味着,当发出update:modelValue事件时,您发出的值将直接分配给myArr变量,有效地替换整个reactive变量而不触发反应链,因为它不会通过代理发生。

If myArr would be a ref([]) vue detects it and the handler function looks something like this:如果myArrref([]) vue 检测到它并且处理程序 function 看起来像这样:

$event => (exp? (exp).value = $event: null) where exp is the expression in the directive $event => (exp? (exp).value = $event: null)其中 exp 是指令中的表达式

which means that the value gets assigned through the ref proxy, triggering the reactivity chain.这意味着该值是通过 ref 代理分配的,从而触发了反应链。

But there is no internal logic that checks if the passed expression is an array and if so, does some splice push magic to keep the original variable, you have to do that yourself.但是没有内部逻辑来检查传递的表达式是否是一个数组,如果是,是否有一些拼接推送魔法来保留原始变量,你必须自己做。

Possible Solutions:可能的解决方案:

1) use an object key: 1) 使用 object 密钥:

 <test-component v-model="myArr.data"/>

 ...

 const myArr = reactive({
    data: [1,2,3]
 });

2) use a custom handler function: 2)使用自定义处理程序 function:

 <test-component :modelValue="myArr" @update:modelValue="onChange"/>

 ...

 const myArr = reactive([1,2,3]);

 function onChange(newval){
   myArr.splice(0, myArr.length, ...newval);
 }
For Options API对于选项 API

I had the same problem using options API and came by this solution.我在使用选项 API 时遇到了同样的问题,并通过了这个解决方案。

The main problem is with the proxy object that is being passed to parent component when emitting the event.主要问题在于在发出事件时传递给父组件的代理 object。

So make sure to pass plain array using this technique:因此,请确保使用此技术传递普通数组:

this.$emit('update:modelValue', JSON.parse(JSON.stringify(this.tags)));

In this code sample, the tags is the array that is being updated and pushed new value into that I want to be also reflected in the model provided by parent component.在此代码示例中,标签是正在更新并推送新值的数组,我希望也反映在父组件提供的 model 中。

Note: Theoretically this solution also works for Composition API but I haven't tested it with Composition API.注意:理论上,该解决方案也适用于 Composition API,但我尚未使用 Composition API 对其进行测试。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM