【问题标题】:What is the correct way to update an array child to parent in Vue JS在Vue JS中将数组子项更新为父项的正确方法是什么
【发布时间】:2018-05-12 19:08:43
【问题描述】:

所以我正在学习 Vue.js,经过一番努力,我(不知何故)得到了以下代码工作。我知道如果它有效,它并不愚蠢,但是我想帮助我改进我的代码,因为我怀疑我是否采取了正确的方法。

以下代码允许用户通过单击按钮来添加 Item 组件的多个实例。 Item 中的 name 字段的输入被传递给一个对象,该对象被插入一个数组中,该数组被发送回父组件。

我对这种方法的主要问题是 items 数组作为道具在 Item 的所有实例之间共享,这是不必要的。但是,我无法提出另一个解决方案,因为我只知道如何通过将数据作为道具传递并更新来在组件之间共享数据。我还读到道具只能由父母更新,所以我猜我也违反了该规则。

有人可以教我一个更好的方法吗?

父代码

<template>

    <div class="items">
         <div v-for="n in itemCount">
            <Item :count="n" :items="items"  />
         </div>
    </div>

    <button @click="addItem">Add item</button>

</template>

<script>
    import Item from './../components/Item'; //the child 

    export default {

        components: {
            Item
        },

        data() {
            return {
                itemCount: 1,
                items: [],
            }
        },

        methods: {
            addItem() {
                this.itemCount ++;
            }
        }

    }
</script>

儿童

<template>

    <div class="item">
        <label>Item name</label>
        <input type="text" v-model="name" @input="update(count)" />    
    </div>

</template>

<script>
    export default {

        props: ['items','count'],

        data() {
            return {
                name: '',
            }
        },

        methods: {

            createItem(index) {
                return {
                    index: index-1,
                    name: this.name,
                }
            },

            update(index) {
                const item = this.createItem(index);
                this.$set(this.items, index-1, item);
            },
        }
    }
</script>

【问题讨论】:

    标签: javascript vue.js vue-component


    【解决方案1】:

    您有理由对最初的实施感到不舒服。理想情况下,子组件不应该假设任何关于它的父组件。在这种情况下,子组件只是呈现&lt;label&gt; 和&lt;input&gt; 供用户输入项目名称。它不应该知道或关心有多个项目。这是创建此类组件的一种方法。它有效地定义了自己的模型,并将该模型简单地反映到&lt;input&gt;:

    Vue.component('custom-item', {
      props: {
        value: String
      },
      template: `
        <div class="custom-item">
          <label>Item name</label>
          <input
            type="text"
            :value="value"
            @input="$emit('input', $event.target.value)"
          >
        </div>
      `
    });
    

    然后父组件简单地将适当的v-model 提供给子元素:(请注意,我已将&lt;button&gt; 移动到根元素内,因为模板不能有多个直接子元素。)

    Vue.component('custom-items', {
      data() {
        return {
          items: []
        };
      },
      methods: {
        addItem() {
          items.push({
            index: items.length,
            name: ""
          });
        }
      },
      template: `
        <div class="custom-items">
          <div v-for="item in items">
            <custom-item v-model="item.name"/>
          </div>
          <button @click="addItem">
            Add item
          </button>
        </div>
      `
    });
    

    该代码对 items 对象使用相同的结构,但您似乎不太可能真正需要 .index 属性,在这种情况下,items 可能只是一个字符串数组而不是对象。

    此外,除非您在样式方面做一些时髦的事情,否则您实际上并不需要在每个自定义项周围使用 &lt;div&gt; 包装器,因此您可以为简单起见放弃它:

        <div class="custom-items">
          <custom-item
            v-for="item in items"
            v-model="item.name"
          />
          <button @click="addItem">
            Add item
          </button>
        </div>
    

    上面可能有一些错别字,因为我没有测试过,但我想你能明白。

    【讨论】:

    • 谢谢!不知道为什么我没有想到更新父数组。我在 mount() 上调用了父级的 addItem,所以我已经有了一个 Item 实例,就像我的方法一样。剩下的唯一问题是,现在我不知道如何在子组件上添加更多元素(即 2 个输入元素,例如项目名字/姓氏),因为单个输入元素的值在组件中传递。在我的方法中,我会在 createItem() 中返回一个额外的属性。你能详细说明一下吗?
    猜你喜欢
    • 2023-02-02
    • 1970-01-01
    • 2019-10-19
    • 1970-01-01
    • 2020-04-16
    • 1970-01-01
    • 1970-01-01
    • 2020-06-18
    • 2019-05-02
    相关资源
    最近更新 更多