VueJS - 使用子组件时如何正确使用 v-model

VueJS - How to use v-model in the right way when using child components

嗯,我是 VueJS 的新手.. 现在我正在学习组件的工作方式。

当我尝试更新传递给子组件的父数据参数时,我感到困惑,该子组件在子组件中用作 v-model。

我将添加一个示例,以便您理解我在说什么(我很难解释自己)

注意:我使用数组作为 v-model,因为我需要一种方法来遍历所有复选框 v-model 并稍后更新它们

我要展示的例子是在旅途中写的。所以这不是实际代码,但您可以从中获得概念。

假设我们有模板:

<script type="x-template id="tree">
    <table>
        <thead>
            <tr>
                <th>Tree-Item</th>
                <th>check chilld</th>
            </tr>
        </thead>
        <tbody>
            <template v-for="child in item.childrens">
                <tr v-if="child.childrens.length <= 0">
                    <td>{{child.name}}</td>
                    <td>
                        <input type="checkbox" v-model="checkboxes[child.id].value" :value="1" />
                    </td>
                </tr>
                <tr v-else>
                    <td colspan="2">
                        <tree :item="child" :checkboxes="checkboxes"></tree>
                    </td>
                </tr>
            </template>
        </tbody>
    </table>
</script>

组件:

    Vue.component("tree", {
        template: "#tree",
        props: {
            item: Object,
            checkboxes: []
        }
    }

vue 对象

    var mainVue = new Vue({
        el: "#app",
        data: {
            treeData: {
                id: 0,
                name: "a name",
                childrens: [
                    {
                        id: 1,
                        name: "b name",
                        childrens: []
                    }, {
                        id: 2
                        name: "c name"
                        childrens: [
                            {
                                id: 3,
                                name: "d name",
                                childrens: []
                            },
                            {
                                id: 4,
                                name: "d name",
                                childrens: []
                            },
                            {
                                id: 5,
                                name: "d name",
                                childrens: []
                            }
                        ]
                    }
                ]
            },
            checkboxes: []
        }, mounted: function() {
            //looping all the childrens... setting checkboxes array to contain data for each index of child
            // checkboxes array now contains the objects of - [{value: 0},{value: 0},{value: 0},{value: 0},{value: 0},{value: 0}]
        }
    });

我的应用看起来像:

    <div id="app">
        <tree :item="treeData" :checkboxes="checkboxes"></tree>
    </div>

现在可以使用了。如果我将挂载函数中的数组值之一更改为 1,它将被设置为已选中。但我的问题是我也想实时更新它。

所以如果我有一个按钮让我们说:

    <div id="app">
        <tree :item="treeData" :checkboxes="checkboxes"></tree>
        <button @click="changeCheckboxes">a button</button>
    </div>

我将添加一种方法来将“复选框”数组更改为新的内容:

changeCheckboxes: function() {
    this.checkboxes = [{value: 1}, {value: 0}, {value: 1}, {value: 0}, {value: 1}, {value: 0}];
}

它不会更新组件,我看不到任何效果..即使我使用 this.$forceUpdate()

所以在我向您介绍了详细信息之后。 是否有任何选项可以直接从根 vue 应用程序更新子组件中的 v-model?

感谢您的宝贵时间!希望我们能弄清楚:)

https://vuejs.org/v2/guide/reactivity.html#For-Arrays

Vue cannot detect the following changes to an array:

  1. When you directly set an item with the index, e.g. vm.items[indexOfItem] = newValue
  2. When you modify the length of the array, e.g. vm.items.length = newLength

问题是你在做v-model="checkboxes[child.id].value"。 V-model 实际上只是一种奇特的做法:

 <input type="checkbox" :value="checkboxes[child.id].value" @input="checkboxes[child.id].value = $event"

你 v-model 中的 @input 部分是 Vue 无法检测到的。我认为对于这个问题,如果你需要将复选框和项目分开,并且你不想重写很多,你必须放弃 v-model 并分别使用 value 和 @input:

 <input type="checkbox" :value="checkboxes[child.id].value" @input="toggleCheckbox(child.id)"
methods: {
  toggleCheckbox(index) {
   this.checkboxes.splice(index, 1, !this.checkboxes[index].value)
  }
}

如果我理解正确的话,child.id 与复选框数组中的索引相关。

然而

我看到你实际上是在改变你的道具,这在 Vue 中是一种不好的做法。 您应该使用 prop/emit 工作流程。这意味着 parent 应该始终负责数据更改。

所以最好的方法是更改​​上面的 toggleCheckbox 函数以发出更改,然后让 parent 改变复选框数组。 parent 执行此操作后,child 也会自动更改。

正如 Sølve Tornøe 已经回答的那样,在 Vue 中,反应性是一个需要注意的问题,特别是对于数组 here。这也是您更新后的 Array 不起作用的原因。

但是,您的问题的解决方案非常简单,不需要太多。让我们仔细看看您的复选框。

<input type="checkbox" v-model="checkboxes[child.id].value" :value="1" />

虽然最初看起来不错,但由于上述反应性问题,您的 v-model 绑定不会更新您的数组值。相反,添加一个额外的 @update 绑定以及循环的索引。

<input type="checkbox" v-model="checkboxes[child.id].value" :value="1" @input="updateCheckbox(i, child.id)" />

您的方法可能如下所示

updateCheckbox(i, id) {
  this.$set(item.childrens[i], id, 'some value here');
}