【问题标题】:Deleting vue component from list always delete the last element in list从列表中删除 vue 组件总是删除列表中的最后一个元素
【发布时间】:2018-10-14 03:49:00
【问题描述】:

我已阅读使用 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>

【问题讨论】:

  • 有几个可用的 JsFiddle 可以显示同样的问题已解决。我的代码似乎一切正常,但在 Chrome 中仍然无法运行......但我遇到的 jsFiddle 在同一个 chrome 浏览器中运行良好。
  • 我让它在 JSFiddle 中工作 jsfiddle.net/andy1234/3f8ct86o
  • 另外,如果您正在做相当复杂的事情,我建议您使用 Object 将您的组件存储为 {UniqueKey: VueComponent, ...} 然后为 Object 执行 v-for,因为它似乎可以工作与 Array 相比更好。

标签: vue.js vuejs2 vue-component


【解决方案1】:

我发现,如果您有另一个更新的 :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>

【讨论】:

    【解决方案2】:

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

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

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

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

    看下面的demo,我添加了一个输入并绑定了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>

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-07-07
      • 1970-01-01
      • 2018-03-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多