从列表中删除vue组件始终会删除列表中的最后一个元素

时间:2018-05-03 18:27:07

标签: vue.js vuejs2 vue-component

我已阅读使用v-for here在列表中呈现自定义组件的文档。

但由于某种原因,我无法使其工作。它总是删除最后一个组件而不是我在索引中发送的组件。知道为什么它不起作用吗?

我的VUE JS版本是:2.5.16。

使用PHPStorm IDE并在docker(linux容器)上运行

和Laravel混合(我在" laravel-mix":" 0。*" 在package.json中输入)以使用webpack并编译JS模块。

这是我的一些代码

// Parent Component JS
<template>
    <ul>
        <li
            is="child-component"
            v-for="(child, index) in componentList"
            :key="index"
            :myVal="Something...."
            @remove="dropField(index)"
            @add-custom-field="addField"
        ></li>
    </ul>
</template>

<script>
    import childComponent from './ChildComponent';

    export default {
        name: 'CustomList',

        components: {'child-component' :childComponent},

          data() {
            return {
                componentList: []
            }
          },

       methods: {
            addField() {
                console.log('Handling add-custom-field  field...');
                this.componentList.push(childComponent);
            },

            dropField(index) {
                console.log(`I am deleting the component with index = ${index}  from listview in parent...`);
                this.componentList.splice(index, 1); 
            }
        }
    }


// Child Component JS

<template>
    <div>
       <input type="text" v-model="currentValue" /><button @click.prevent="$emit('remove')" > Remove </button>
    </div
</template>
<script>
  export default {
     props: { myVal : '' },
     data() { return { currentValue: ''} },
     created() {this.currentValue = this.myVal;}

  }
</script>

2 个答案:

答案 0 :(得分:2)

问题是由v-for 的就地补丁“策略引起的。这意味着当从componentList中删除一个元素时,Vue不会重建所有子元素。

检查Vue Guide on an “in-place patch” strategy for v-for

  

当Vue更新使用v-for,by的呈现的元素列表时   默认情况下,它使用“就地补丁”策略。如果是数据的顺序   项已更改,而不是移动DOM元素以匹配   物品的顺序,Vue将就地修补每个元素并确保   它反映了应该在该特定索引处呈现的内容。

实际上你已经删除了最后一项,但问题是第一个和第二个孩子的data property = currentValue在首次安装时是'a','b'。稍后当Vue重新渲染(删除最后一个子节点)时,虽然prop = myVal已经改变,但data property = currentValue保持相同的值。

看下面的演示,我添加了一个输入并绑定myVal,你会看到差异。

Vue.config.productionTip = false

let childComponent = Vue.component('child', {
  template: `<div class="item">
      <p>Index:{{parentIndex}} => <button @click.prevent="removed()" > Remove </button>
      Data:<input type="text" v-model="currentValue" />Props:<input type="text" v-bind:value="myVal" />
      </p>       
    </div>`,
     props: { 'myVal':{
          type: String,
          default: ''
        } ,
        'parentIndex': {
          type: Number,
          default: 0
        }
      },
     data() {
       return { 
        currentValue: ''
       } 
     },
     mounted() {
      this.currentValue = this.myVal
     },
     methods: {
      removed: function () {
        this.$emit('remove')
      }
     }
})


app = new Vue({
  el: "#app",
  data() {
    return {
        componentList: ['a', 'b', 'c'],
        componentType:childComponent
    }
  },

  methods: {
    addField() {
        console.log('Handling add-custom-field  field...');
        this.componentList.push(childComponent);
    },

    dropField(index) {
        console.log(`I am deleting the component with index = ${index}  from listview in parent...`);
        this.componentList.splice(index, 1); 
    }
  }
})
li:nth-child(odd) {
  background-color:#d0d5dd;
}
<script src="https://unpkg.com/vue@2.5.16/dist/vue.js"></script>
<div id="app">
    <ul>
        <li v-for="(child, index) in componentList"><div
            :is="componentType"
            :key="index"
            :my-val="child"
            :parent-index="index"
            @remove="dropField(index)"
            @add-custom-field="addField"
        >{{child}}</div></li>
    </ul>
</div>

答案 1 :(得分:0)

我发现,如果您还有另一个更新的:key属性(非索引),它将可以根据需要工作

这是我的例子

<template>
    <div id="app">
        <ul>
            <li
                v-for="(teacher, index) in teachers_list"
                v-bind="teacher"
                :key="teacher.id"
            >
            <p>Teacher id {{teacher.id}}</p>
            <button @click="deleteTeacher(index)"></button>
            </li>
        </ul>
    </div>
</template>

<script>
export default {
    data() {
        return {
                teachers_list: [
                {name: 'teacher a', id: 100},
                {name: 'teacher b', id: 200},
                {name: 'teacher c', id: 300},
            ]
        }
    },
    methods: {
        deleteTeacher(index) {
            console.log(index);

            this.teachers_list.splice(index, 1)
        }
    }
}
</script>