v-for 中的 key

2018-07-01  本文已影响0人  围观工程师

vue官方文档不推荐使用 index 作为 v-for 的 key,一直不明白为什么,开发中也没有碰到相关问题,今天终于在知乎上碰到了这个问题。

见vvpvvp在问题中的回答

答主提供的测试代码

html

<div id="app">
  <test v-for="(item,index) in list" :key="index">
     <input v-model="item.value" type="input"/>          <button @click="remove(index)">delete</button>
  </test>
  <button @click="add()">add</button>
</div>

js

Vue.component('test', {
  template: '<div><slot></slot><a @click="change">{{a}}</a></div>',
  data: function() {
    return {
      a: "click Me!"
    }
  },
  methods: {
    change: function() {
       this.a = "clicked";
    }
  }
});
new Vue({
  el: '#app',
  data: {
    list: []
  },
  methods: {
    add: function() {
      this.list.push({
        value: 1
      });
    },
    remove: function(index) {
      this.list.splice(index, 1);
    }
  }
})

问题重现

点击add * 3,点击后两个 “click Me!” 使其状态改变,点击第一个 delete

问题出在哪

看了一遍回答中的评论大致明白了原因。由于使用了 index 作为 key ,当删除第一个 test 组件后,第二个 test 组件的 key 由原来的 1 变成了 0 ,第三个 test 组件的 key 由原来的 2 变成了 1 。diff (虚拟DOM的Diff算法,见原问题第一个回答) 发现少了值为 3 的 key ,于是删除其对应的 test 组件,导致了这个问题。

我为什么没触发过这个问题

由于业务原因,我的子组件状态通常取决于父组件data的属性值,即子组件状态不是独立的,需要依赖父组件数据。这使得即使由于 index 导致“删错了”子组件,父组件的数据也会重新同步给子组件,保持子组件状态与父组件数据一致。代码大致如下:

html

<div id="app">
  <test v-for="(item,index) in list" :a="item.a" :key="index" @change="change(index)">
     <input v-model="item.value" type="input"/>          <button @click="remove(index)">delete</button>
  </test>
  <button @click="add()">add</button>
</div>

js

Vue.component('test', {
  template: '<div><slot></slot><a @click="change">{{a}}</a></div>',
  props: ['a'],
  methods: {
    change: function() {
       this.$emit('change')
    }
  }
});
new Vue({
  el: '#app',
  data: {
    list: []
  },
  methods: {
    add: function() {
      this.list.push({
        value: 1,
        a: 'click Me!'
      });
    },
    remove: function(index) {
      this.list.splice(index, 1);
    },
    change (i) {
      this.list[i].a = 'clicked'
    }
  }
})

为什么不推荐使用 index

上面说到,由于 index 导致“删错了”子组件,父组件的数据会重新同步给子组件,保持子组件状态与父组件数据一致。如果使用唯一 id 那么 vue 就不必多做数据同步这一步操作。

上一篇 下一篇

猜你喜欢

热点阅读