在Vue JS中将数组子项更新为父项的正确方法是什么

Fra*_*ank 1 javascript vue.js vue-component

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

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

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

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

父代码

<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>
Run Code Online (Sandbox Code Playgroud)

孩子

<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>
Run Code Online (Sandbox Code Playgroud)

Ste*_*mas 5

您对最初的实施感到不舒服是有道理的。理想情况下,子组件不应假设其父组件的任何内容。在这种情况下,子组件只是渲染一个<label><input>让用户输入项目名称。它不应该知道或关心有多个项目。这是创建此类组件的一种方法。它有效地定义了自己的模型,并简单地将该模型反映到<input>

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>
  `
});
Run Code Online (Sandbox Code Playgroud)

然后父组件简单地为子组件提供适当v-model的:(请注意,我已经移动<button>了根元素的内部,因为模板不能有多个直接子元素。)

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>
  `
});
Run Code Online (Sandbox Code Playgroud)

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

此外,除非您在样式上做一些时髦的事情,否则您实际上并不需要<div>每个自定义项目的包装器,因此为了简单起见,您可以放弃它:

    <div class="custom-items">
      <custom-item
        v-for="item in items"
        v-model="item.name"
      />
      <button @click="addItem">
        Add item
      </button>
    </div>
Run Code Online (Sandbox Code Playgroud)

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