2

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

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

我的 VUE JS 版本是:2.5.16。

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

和 Laravel 混合(我在 package.json 中有"laravel-mix": "0.*"条目)使用 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>
4

2 回答 2

3

我发现如果您有另一个更新的: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>
于 2019-10-05T21:55:48.487 回答
3

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

检查v-for 的“就地补丁”策略的 Vue 指南

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

实际上你已经删除了最后一项,但问题是第一个和第二个孩子的数据属性 = 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>

于 2018-05-03T19:03:15.290 回答