【问题标题】:Strange behavior when removing an object from an array of objects in Vue从Vue中的对象数组中删除对象时的奇怪行为
【发布时间】:2018-05-13 14:08:30
【问题描述】:

我有一个 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)。我只是不知道发生了什么。

我的数组拼接代码似乎也可以正常工作。我在拼接功能后控制台记录了更新的数组,它只包括 iPad 和 AirPods(正确),但奇怪的是,视图不同!有人可以告诉我我在这里做错了什么吗?谢谢。

【问题讨论】:

    标签: javascript vue.js vuejs2


    【解决方案1】:

    您应该使用: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

    【讨论】:

    • 很好的答案。尽量避免在不必要时使用小提琴。
    【解决方案2】:

    如果您将 localProduct 从数据属性更改为计算属性,您可以保持其余代码相同,并且它似乎可以工作。只需在道具和模板之间弹出这个人来代替数据。

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

    【讨论】:

    • 这成功了!任何解释为什么这与我的代码相反?
    • 我认为这与 Vue 文档的 Computed Caching 部分有关,但我不是 100% 确定
    猜你喜欢
    • 2017-11-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-03-07
    • 2018-07-25
    • 1970-01-01
    • 2020-08-14
    • 1970-01-01
    相关资源
    最近更新 更多