在v-for组件中删除了错误的项目[在v-for中选择了正确的:key]

时间:2018-08-09 06:41:02

标签: caching vue.js vue-component v-for virtual-dom

我有两个组件,如下所示:

     Vue.component('comp-child', {
         template: `<div>{{childData.name}}<slot></slot>{{randomNum}}</div>`,
         props: {
             parentData: {
             }
         },
         data() {
             return {
                 childData: {},
                 randomNum: Math.round(Math.random() * 100)
             };
         },
         created() {
             this.childData.name = this.parentData.name;
         }
     });
     Vue.component('comp-parent', {
         template: `<div><component v-for="(item, index) in arr" is="comp-child" :key="index" :parent-data="item">
             <button @click="deleteItem(index)">delete</button>
         </component>
         </div>`,
         data(){
             return {
                 arr: [{
                     name:1
                 }, {
                     name:2
                 }, {
                     name:3
                 }, {
                     name:4
                 }, {
                     name:5
                 }]
             };
         },
         methods: {
             deleteItem(index) {
                 this.arr.splice(index, 1);
                 console.log(`${index}th element deleted! `);
               
             }
         }
     });
     let app = new Vue({
         el: '#app'
     });
<script src="https://unpkg.com/vue"></script>

<div id="app">
    <comp-parent></comp-parent>
</div>

在此演示中,无论您单击哪个项目,总是删除最后一个项目。

我找到了由key的{​​{1}}引起的这个问题,如果使用v-for作为键,则会发生此问题,但使用其他值作为键(如字符串),则可以正常工作;

1, 2, 3, 4,..

检查此小提琴:demo

是由虚拟DOM引起的吗?似乎VUE将键和子组件绑定为缓存,当template: `<div><component v-for="(item, index) in arr" is="comp-child" :key="item.key" :parent-data="item"> <button @click="deleteItem(index)">delete</button> </component> </div>`, data(){ return { arr: [{ name:1, key: 'key1' }, { name:2, key: 'key2' }, { name:3, key: 'key3' }, { name:4, key: 'key4' }, { name:5, key: 'key5' }] }; }, 发生更改时,如果arr中的某些项只是按索引(1,2,3,..)的顺序重新呈现组件。删除后,arr的长度减小,导致无法渲染最后一个。

请有人向我解释一下,谢谢!

1 个答案:

答案 0 :(得分:0)

使用v-for时,您的密钥必须是有关项目唯一的一些数据。索引不好,因为它不能识别项目。只需将键更改为item.name即可使您的示例完美运行。

在您的示例中,您的源数组已被正确修改,但是vue正在重用以前生成的组件实例以显示修改后的数组,并且这些实例具有剩余状态。 Vue这样做是出于性能方面的考虑,通常这不是问题,但确实突出了选择正确密钥的重要性。

由于您在自然界中很少见到的一些小事情,使您的问题变得更糟,您应该避免...在创建的挂钩中将parentData.name分配给childData.name:因为您的孩子是被重用,而不是重新创建,childData.name变得陈旧。随机数也是如此。

Vue.component('comp-child', {
         template: `<div>{{childData.name}}<slot></slot>{{randomNum}}</div>`,
         props: {
             parentData: {
             }
         },
         data() {
             return {
                 childData: {},
                 randomNum: Math.round(Math.random() * 100)
             };
         },
         created() {
             this.childData.name = this.parentData.name;
         }
     });
     Vue.component('comp-parent', {
         template: `<div><component v-for="(item, index) in arr" is="comp-child" :key="item.name" :parent-data="item">
             <button @click="deleteItem(index)">delete</button>
         </component>
         </div>`,
         data(){
             return {
                 arr: [{
                     name:1
                 }, {
                     name:2
                 }, {
                     name:3
                 }, {
                     name:4
                 }, {
                     name:5
                 }]
             };
         },
         methods: {
             deleteItem(index) {
                 this.arr.splice(index, 1);
                 console.log(`${index}th element deleted! `);
               
             }
         }
     });
     let app = new Vue({
         el: '#app'
     });
<script src="https://unpkg.com/vue"></script>

<div id="app">
    <comp-parent></comp-parent>
</div>