Vue `v-for、 v-if` 等key值绑定index和唯一id值时的对照测试

734 阅读1分钟
<!-- item.vue 监听数据 -->
<template>
  <div> {{ 'obj' + obj }}、{{ 'id' + id }}、{{ data }} </div>
</template>
<script>
import leftConsoleMixin from '@/mixin/leftConsole'
let key = 1
export default {
  name: `item`,
  mixins: [leftConsoleMixin],
  props: {
    obj: Object,
    id: [String, Number]
  },
  data() {
    return {
      data: key++,
      tag: this.$vnode.tag
    }
  },
  watch: {
    obj: {
      handler(newVal) {
        if (newVal) {
          console.log(this.tag, 'watch', this.data)
        }
      },
      immediate: true,
      deep: true
    },
    id: {
      handler(newVal) {
        if (newVal) {
          console.log(this.tag, 'watch', this.data)
        }
      },
      immediate: true
    }
  }
}
</script>
执行操作
  1. 数组方法和数组下标更改
  2. 模拟分页情况
  3. 数组内容不变,下标发生改变
  4. 叠加2和3
  5. 深层次的obj对象变更
  6. 通过set方法变化
测试数据
{
  lists: [
    { id: 1, a: 1, b: 1, c: 1 },
    { id: 2, a: 1, b: 1, c: 1 },
    { id: 3, a: 1, b: 1, c: 1 }
  ],
  temp: [
    { id: 1, a: 1, b: 1, c: 1 },
    { id: 2, a: 1, b: 1, c: 1 },
    { id: 3, a: 1, b: 1, c: 1 }
  ],
  deepObj: [{ a: [{ b: [{ d: 1 }], c: 1 }] }]
}
场景一:
key值为index的情况,传的属性为obj
<div>
  <item v-for="(obj, index) in lists" :key="index" :obj="obj"/>
</div>
      
key值为id的情况,传的属性为obj
<div>
  <item v-for="obj in lists" :key="obj.id" :obj="obj" />
</div>

image-20210917103413962.png

image-20210917103424152.png

image-20210917103434212.png

image-20210908201827626.png

image-20210917103448491.png

image-20210917103511692.png

lists.splice(0,1)

index时触发1,2组件的watch,删除3

id时删除4

list.reverse()

index时触发1,3watch

id时直接更换位置

key为id时能够准确操作组件 index时则是通过变换传入对值进行复用

场景二:
key值为id的情况,传的属性为基础数据类型id
<div>
  <item v-for="{ id } in lists" :key="id" :id="id" />
</div>
​
key值为index的情况,传的属性为基础数据类型id
<div>
  <item v-for="({ id }, index) in lists" :key="index" :id="id" />
</div>

image-20210917103533080.png

image-20210917103852744.png

image-20210917103902719.png

image-20210908202041883.png

image-20210917111322525.png

image-20210917103926694.png

lists.splice(0,1)

index时删除3,更新1,2值

id删除4

lists=temp

引用地址变了,传值不变,不触发更新

场景三:
key值为index的情况,不传的属性
<div>
  <item v-for="(obj, index) in lists" :key="index"/>
</div>
​
key值为id的情况,不传的属性
<div>
  <item v-for="obj in lists" :key="obj.id" /></div>

image-20210917103234430.png

image-20210917103300393.png

image-20210917103320012.png

image-20210908201737572.png

image-20210917103347052.png

image-20210917111622899.png

list.reverse()

传入值不变,不触发更新

lists=temp

引用地址变了,传值不变,不触发更新

lists.push(lists.shift())

传入值不变,不触发更新

结论:
  1. key为唯一值时渲染时会变换组件的位置,而使用index做key时则是改变传入到组件的值
  2. 传入组件的值没有发生变化时,外层对象的引用地址发生变化,不会触发组件更新