【Vue】为什么在使用v-for的时候需要指定key属性?

2 篇文章 0 订阅

这个问题涉及到了虚拟Dom的更新过程和策略。当渲染的数据发生改变时,会生成新的虚拟Dom树和老的虚拟Dom树进行比较,返回对Dom树的更新操作。

以列表渲染为例,如果数据项的顺序被改变,为了尽量减少Dom的渲染操作,Vue将不是移动DOM元素来匹配数据项的改变(更不是全部销毁重新渲染),而是简单复用此处每个元素,并且确保它在特定索引下显示已被渲染过的每个元素,即就地复用策略。
比如:
在这里插入图片描述
在BC中间插入一个新的节点,如果不指定key,在页面Dom的真实变更如下:
在这里插入图片描述
原来ACBDE的Dom其实没有变化,只是在最后增加一个Dom,将原来显示C的Dom显示的内容改为显示F,依次类推。就是说,原来显示C对应的Dom假设在浏览器中的ID是C_dom,更新后显示C的Dom对应的ID就变成D_dom了。这样的方式其实不是更新的最优解。

有一个严重的问题就是,v-for如果不指定key,如果列表不只是展示功能,而是有勾选选中功能时,更新前后会导致选中项的错误变化。比如下面这个例子,一个可勾选的列表,可以动态的在列表顶端增加项。(代码在文末提供)
在这里插入图片描述
在选中第二项(JAVA)后,增加一项被选中的项变成了JS,依然是列表的第二项!
在这里插入图片描述
换一种方式,我们把修改第二项的样式,然后增加顶部增加一项
在这里插入图片描述
得到的结果依然和前面类似。也就是说,Dom一些属性没有跟随列表的更新过程中随着Dom树的更新跟着对应的内容更新,而是绑定在Dom上。当为v-for增加key属性后,这样的“bug”消失了。增加key属性后,列表项能绑定Dom节点,diff算法能跟踪每个节点的身份,从而重用和重新排序现有元素。

值得注意的是,如果key使用列表的index绑定,可能达不到想要的效果。因为index在列表改变的时候一起改变了,达不到作为列表项唯一标识的目的。

<div v-for="(item, index) in list" :key="index" >

为了给 Vue 一个提示,以便它能跟踪每个节点的身份,从而重用和重新排序现有元素,你需要为每项提供一个唯一 key attribute。建议尽可能在使用 v-for 时提供 key attribute,除非遍历输出的 DOM 内容非常简单,或者是刻意依赖默认行为以获取性能上的提

以上内容根据其他博客整理,经过自己的验证,增加自己的思考。如果有错误欢迎指正。

附录

<template>
  <div id="app">
    <label >Range:</label><input type="text" v-model="count"><br>
    <label >Name:</label><input type="text" v-model="name">
    <input type="button" value="添加" @click="add">
    <div v-for="item in list" >
      <input type="checkbox">[{{item.count}}]——{{item.name}}
    </div>
  </div>
</template>
<script>
export default {
  name: 'ListRend',
  data () {
    return {
      count: '',
      name: '',
      list: [
        {count: 1001, name: 'JS'},
        {count: 1002, name: 'JAVA'},
        {count: 1003, name: 'C#'},
        {count: 1004, name: 'C++'},
        {count: 1005, name: 'C'}
      ]
    }
  },
  methods: {
    add () {
      let p = {
        count: this.count,
        name: this.name
      }
      this.list.unshift(p)
    }
  }

}
</script>
  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值