从Vue中的对象数组中删除对象时的奇怪行为

时间:2017-11-29 19:07:25

标签: javascript vue.js vuejs2

我有一个Vue组件和一个根Vue实例。该实例包含一组对象(用于产品),该组件使用每个产品的v-for循环显示在我的HTML中。这就是products.js的样子:

/**
 * Component to show products
 */
Vue.component('product', {
    props: ['product'],
    data: function() {
        return {
            localProduct: this.product
        };
    },
    template: `<div class="products">
                    <span>{{ localProduct.product }}</span>
                    <a href="javascript:void" v-on:click="remove">Remove</a>
                </div>`,
    methods: {
        remove: function() {

            var removeIndex = productsList.products.map(function(i) { return i.id; }).indexOf(this.localProduct.id);
            productsList.products.splice(removeIndex, 1);
        }
    }
});

/**
 * Instantiate root Vue instance
 */
var productsList = new Vue({
    el: '#products',
    data: {
        products: [{ id: 1, product: 'iPad' }, { id: 2, product: 'iPhone' }, { id: '3', product: 'AirPods' }]
    }
});

现在,循环为iPad,iPhone和AirPods呈现3个DIV。有点奇怪的是,当我点击iPhone的移除按钮(productsList.products [1])时,HTML会显示iPad和iPhone而不是iPad和AirPods(因为我们删除了iPhone)。我无法弄清楚发生了什么。

我的阵列拼接代码似乎也正常工作。我在splice函数之后安装了更新的数组,它只包括iPad和AirPods(正确),但奇怪的是,视图不同!有人能告诉我这里我做错了什么吗?感谢。

2 个答案:

答案 0 :(得分:4)

您应该使用:key来跟踪元素。

<product v-for="product in products"
         :product="product"
         :key="product.id"
         v-on:remove="removeProduct"></product>

我在这里举了一个例子。

/**
 * Component to show products
 */
Vue.component('product', {
    props: ['product'],
    data: function() {
        return {
            localProduct: this.product
        };
    },
    template: `<div class="products">
                    <span>{{ localProduct.product }}</span>
                    <a href="javascript:void" v-on:click="remove">Remove</a>
                </div>`,
    methods: {
        remove: function() {
        	this.$emit('remove', this.localProduct.id);
        }
    }
});

/**
 * Instantiate root Vue instance
 */
var productsList = new Vue({
    el: '#products',
    data: {
        products: [{ id: 1, product: 'iPad' }, { id: 2, product: 'iPhone' }, { id: '3', product: 'AirPods' }]
    },
    methods: {
    	removeProduct: function(id) {
      this.products = this.products.filter(function(p) {
      	return p.id !== id;
      });
      }
    }
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.9/vue.min.js"></script>
<div id="products">
<product v-for="product in products"
         :product="product"
         :key="product.id"
         v-on:remove="removeProduct"></product>
</div>

我还对您的代码进行了一些清理工作,例如使用filter()代替splice()。让子组件发出父进程所处的事件而不是直接更改父进程上的数据的子进程。

要详细了解列表呈现check out the docs

答案 1 :(得分:1)

如果将localProduct从数据属性更改为计算属性,则可以使其余代码保持相同,并且似乎可以正常工作。只需在道具和模板之间用数据代替数据。

computed: {
    localProduct: function() {
        return this.product
    }
},