【问题标题】:How can I use a component function in Vue to remove an object from an array in the parent's data?如何在 Vue 中使用组件函数从父数据中的数组中删除对象?
【发布时间】:2020-08-15 07:28:38
【问题描述】:

我觉得你只看相关的VueJS代码会更容易,然后我可以解释一下:

new Vue({
    el: '#app',
    data: {
        history: [
            {name: 'red', value: '#f00'},
            {name: 'not red', value: '#ff0'},
            {name: 'also not red', value: '#f0f'},
        ],
    },
    components: {
        ColorItem: {
            template:
                `<div>
                    <input :value="name">
                    <div class="color-preview" :style="{backgroundColor:hex}"></div>
                    <span v-html="hex"></span>
                    <button @click="$emit('remove')">
                        <i class="fas fa-trash"></i>
                    </button>
                </div>`,
            props: 
                ['mode', 'hex', 'name'],
            methods: {
                removeColor: function(index) {
                    console.log(index);
                    this.history.splice(index, 1);
                }
            },
        }
    },
    // ...
}

在我的 Vue 应用程序中,我在一个名为 history 的变量中的数组中有对象(用名称和值表示颜色)。我正在使用v-for 为历史记录中的每个项目创建一个新的color-item 组件:

<div v-for="(item, index) in history" :key="item.value">
    <color-item mode="history" :name="item.name" :hex="item.value" @remove="removeColor(index)">
    </color-item>
</div>

我正在尝试从列表中删除颜色,我看到了this beautiful example 如何使用 vue 从列表中删除项目,它使用它们的位置并拼接它。我还看到 this SO answer 使用 map 函数获取位置,但是 pos 对我来说是未定义的,因为 e.hex 是未定义的,并且使用检查器我认为这是因为 Vue 在引擎盖下使用了某种吸气剂并且没有'不只是有我的数据。

在有人告诉我在 v-for 循环中使用组件模板之前,我需要该模板,以便我可以将其用于其他颜色列表(例如,收藏夹)。

我是 Vue 的新手,所以请原谅我的措辞不当,感谢我在学习这个框架时获得的所有帮助。

【问题讨论】:

    标签: javascript vue.js vuejs2


    【解决方案1】:

    这里更好的方法是使用子组件中的$emit,并在父组件中监听事件。

    您应该将pos 作为事件传递,然后直接在父组件中更改history 数据

    在您的removeColor 函数中:

    this.$emit('remove-color', pos)
    

    那么在父组件中你应该有:

    <ColorItem v-on:remove-color="removeColorFromHistory" />
    

    并在父组件的方法中更改您的数据:

    methods: {
      removeColorFromHistory(pos) {
        this.history.splice(pos, 1);
      }
    }

    (see documents)

    $parent 用于处理边缘情况,这意味着有时需要稍微改变 Vue 规则的不寻常情况。但是请注意,它们都有缺点或可能存在危险的情况。 *

    【讨论】:

    • 如何从我的模板中传递pos 位置变量?我使用模板在 Vue 中定义了组件 HTML。
    • 我按照建议使用 emit 更新了我的问题,但它仍然无法正常工作。知道为什么吗?
    • @Justin 您必须在父组件中有一个模板,您必须在其中侦听从子组件发出的事件&lt;ColorItem v-on:remove-color="METHOD" /&gt; 这将调用父组件中的 METHOD,您的方法当前位于子组件中.
    【解决方案2】:

    一般来说,子组件不应该直接操作父组件的数据,尤其是通过this.$parent.whatever。你应该保持组件的边界清晰,否则你会让它们紧密耦合。

    所有子组件需要做的就是发出一个remove 事件,告诉父组件它应该从自己的数据(父组件拥有)中删除该项目。

    在子组件中:

    <button @click="$emit('remove')">Remove</button>
    

    然后在父组件中:

    <div v-for="item of history">
      <color-item :hex="item.hex" @remove="removeItem(item)"/>
    </div>
    
    methods: {
      removeItem(item) {
        this.history = this.history.filter(otherItem => otherItem !== item)
    
        // or
        this.history.splice(this.history.indexOf(item), 1)
      }
    }
    

    remove 事件的事件处理程序作为参数传入要移除的项目。

    由于父组件“拥有”history 数组,它应该是唯一改变它的组件。一旦你开始允许随机组件改变它们不拥有的数据,你就会开始得到意大利面条代码,并且很难追踪为什么会发生特定的突变以及是谁改变了它。

    这是一个例子:

    Vue.component('color-item', {
      template: '#color-item',
      props: ['name', 'hex'],
    })
    
    new Vue({
      el: '#app',
      data: {
        items: [
          { name: 'red', value: '#f00' },
          { name: 'green', value: '#0f0' },
          { name: 'blue', value: '#00f' },
        ],
      },
      methods: {
        removeItem(item) {
          this.items.splice(this.items.indexOf(item), 1)
        },
      },
    })
    .name {
      display: inline-block;
      min-width: 50px;
    }
    
    .preview {
      display: inline-block;
      width: 15px;
      height: 15px;
      margin-right: 10px;
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
    
    <template id="color-item">
      <div>
        <span class="name">{{ name }}</span>
        <div class="preview" :style="{ backgroundColor: hex }"></div>
        <button @click="$emit('remove')">Remove</button>
      </div>
    </template>
    
    <div id="app">
      <div v-for="item of items">
        <color-item :name="item.name" :hex="item.value" @remove="removeItem(item)"></color-item>
      </div>
    </div>

    【讨论】:

    • 感谢您的详细回复。我试过了,但没有用;我相信这与需要数组中的对象索引有关,而您只是将颜色项视为基元。
    • 我尝试使用v-for="(item, index) in history" 传递索引,但它没有调用函数
    • 我不会将颜色项目视为基元。 item 是一个对象,不是吗?这应该有效。
    • 我认为由于某种原因没有调用该函数......你能看看我更新的代码吗?
    猜你喜欢
    • 2018-08-27
    • 2015-08-12
    • 2019-03-07
    • 2018-07-25
    • 1970-01-01
    • 1970-01-01
    • 2021-04-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多