Vue array.splice 从列表中删除错误的项目

Vue array.splice removing wrong item from list

我有一个列表,我正在使用 for 循环遍历它。结构如下所示:

salesLists: { 
  1: [ [], [], [] ]
  2: [ [], [] ]
}

和html:

<div v-for="(saleLists, index) in salesLists">
    <my-comp v-for="(item, i) in saleLists" :key="i" :index="parseInt(i)+1"></my-comp>
</div>

现在,我正在尝试从 salesLists[1] 数组中删除项目。我有一个按钮 @click="removeForm":

removeForm(e) {
        var index = parseInt(e.target.getAttribute('data-index')) - 1 // = 2
        var client = e.target.getAttribute('data-client')             // = 1
        //Vue.delete(this.salesLists[client], index);
        this.salesLists[client].splice(index, 1)
        this.$forceUpdate()
}

它删除了它,但是,因为我没有指定任何键并且它只是空数组(我假设),它没有从 DOM 中删除正确的元素。它删除了 2 的索引,但由于它是 v-for 循环遍历该项目,并且计数减少,它最后只删除最后一个项目。

克服这个问题的正确方法是什么? :/

这是一个Fiddle:https://jsfiddle.net/8rvfz40n/ 尝试为每个输入字段写入不同的值并删除中间的值,您会看到它会删除最后一个

我认为这个误导了很多人。

我前段时间在vue论坛写过这个答案 在 https://forum.vuejs.org/t/solved-array-of-components-wrong-after-element-remove/11866/3

so the problem is this

you have an array [rec1,rec2,rec3]

the keys for that array are 0, 1, 2

if you remove item at index of 1 you'd get an array with values [rec1, rec3], however the keys would be [0, 1], as the array does not skip the index after you remove it. Once you're in the template drawing it, since you don't have the key defined, the change the component sees is that the key or index 2 is missing, which is the last item, so it removes it.

要解决这个问题,您需要找到一种不同的方法来确保您定位到预期的项目

https://jsfiddle.net/8rvfz40n/2/

在您的情况下,使用项目 list 而不是索引 i 将删除预期的项目

<div id="app">
  <div v-for="lists in xLists">
    <my-comp v-for="(list, i) in lists" :list="list"></my-comp>
  </div>
</div>

我应该提到另一种选择是以某种方式将唯一键存储在数组中,但正如您所想象的那样,这可能更难维护

您的问题实际上非常简单:您在第一个循环中丢失了对 xLists 中对象键的引用。如果您存储对象键并将其作为道具传递,您将保留该引用:

<div v-for="(saleLists, index) in salesLists">
    <!-- index will refer to the object key -->
    <my-comp v-for="(item, i) in saleLists" :key="i" :index="i+1" :sales-list-index=":index"></my-comp>
</div>

并且您可以简单地检索属性 salesListIndex 并将其用作指向对象中正确嵌套数组的键。目前尚不清楚您的实际示例中的组件是如何编写的,但参考您的 fiddle (我使用字母键以便您可以判断它是对象键还是数组键,但在实现方面它相同):

Vue.component('my-comp', {
  props: ['index', 'value', 'listKey'],
  template: `
   <div>
     <p>xListsKey: {{ listKey }}, index: {{ index }}</p>
     <input :value="value" /> 
      <button :data-index="index" @click="remove">del </button>
    </div>
  `,

  methods: {
    remove(e) {
      var index = e.target.getAttribute('data-index');
      this.$parent.xLists[this.listKey].splice(index, 1)
    }
  }
})

new Vue({
  el: '#app',
  data: {
    xLists: {
      'aa': [
        ['lorem'],
        ['ipsum'],
        ['dolor']
      ],
      'bb': [
        ['foo'],
        ['bar']
      ]
    }
  }
})
<script src="https://unpkg.com/vue"></script>

<div id="app">
  <div v-for="(lists, listKey) in xLists" :key="listKey">
    <my-comp v-for="(list, i) in lists" :key="i" :index="i" :value="list" :list-key="listKey"></my-comp>
  </div>
</div>

<div v-for="(saleLists, index) in salesLists">
    <my-comp v-for="(item, i) in saleLists" :key="i" :index="parseInt(i)+1"></my-comp>
</div>

使用索引作为键是个问题,当你从中间删除一个项目时,丢失的索引是最后一个。

在我的例子中,我找到的解决方案是为项目添加唯一的 "Hash",例如 ID,但如果项目是新闻,则 ID 为空。

我使用的哈希是时间戳:

Hash: new Date().getTime()

然后:

 <div v-for="(saleLists, index) in salesLists">
     <my-comp v-for="(item, i) in saleLists" :key="item.Hash" :index="parseInt(i)+1"></my-comp>
 </div>