• 技术文章 >web前端 >Vue.js

    vue中为什么v-for指令的 key 值不能是 index?

    青灯夜游青灯夜游2022-01-22 15:05:00转载70
    vue中使用v-for时为什么不能用index作为key?下面本篇文章给大家介绍一下 v-for 的 key 值不能是 index 的原因,希望对大家有所帮助!

    为什么 v-for 的 key 值不能是 index?

    很多人一说起这道老生常谈的面试题,马上就开始滔滔不绝地讲述 虚拟DOMdiff算法 了。

    讲这些没问题,但如果是我,一定先讲 v-for 的 key 值写成 index 会造成的问题,再讲原理。

    曾经我写 v-for, key 值永远都是 index,直到有一天,我这么写造成了线上bug...

    来看一下我的线上bug演示吧:

    父组件代码
    <Child
      v-for="(item, index) in list"
      :key="index"
      :count="item.count"
      :name="item.name"
      @delete="handleDelete(index)"
    />
    
    list: [
        {
          count: 1,
          name: '第1个元素'
        },
        {
          count: 2,
          name: '第2个元素'
        },
        {
          count: 3,
          name: '第3个元素'
        }
      ]
      
    handleDelete(index) {
      this.list.splice(index, 1)
    },

    1.gif

    如代码和gif演示,点击删除第2个元素,看上去似乎一切正常。

    等一下,第三个元素的count值居然变成了2,wtf!!!

    惊得我又去看了遍子组件的代码

    子组件
    <div>
      <span>{{ name }}</span>
      count值为:{{ innerCount }}
      <button @click="$emit('delete')">-</button>
    </div>
    
    props: {
      count: {
        type: Number,
        default: 0
      },
      name: {
        type: String,
        default: ''
      }
    },
    data() {
      return {
        innerCount: this.count
      } 
    }

    感觉也没什么不对的啊。

    不信邪,我又多创建了点元素来删除,还试了下排序:

    2.gif

    果然,不光删除元素有问题,排序也有问题。

    把 key 值改成 item.name 再试一下。

    <Child
      v-for="(item, index) in list"
      :key="item.name"
      :count="item.count"
      :name="item.name"
      @delete="handleDelete(index)"
    />

    3.gif

    正常了。

    这样看来,在 v-for 里把 key 值写成 index,非常危险啊。

    在查阅了 vue 官方文档之后,我终于明白了原因:

    当 Vue 正在更新使用 v-for 渲染的元素列表时,它默认使用“就地更新”的策略。如果数据项的顺序被改变,Vue 将不会移动 DOM 元素来匹配数据项的顺序,而是就地更新每个元素,并且确保它们在每个索引位置正确渲染。

    这个默认的模式是高效的,但是只适用于不依赖子组件状态或临时 DOM 状态 (例如:表单输入值) 的列表渲染输出

    不依赖子组件状态

    子组件里有一行很关键的代码

    data() {
      return {
        innerCount: this.count
      } 
    }

    子组件内部定义了 innerCount,这样子组件就有了自己的状态,按照官方文档的说明,这种情况下不能把 index 作为 key 值。

    临时 DOM 状态

    <div v-for="(item, index) in list1" :key="index">
      <input type="text" />
      <button @click="delClick(index)">删除</button>
    </div>

    4.gif

    删除了第2项,但是第3项在表单中的3变成了2,跟上面依赖子组件状态的例子是一样的。

    总结

    写列表渲染时, 依赖子组件状态或临时 DOM 状态的情况,如果有 删除、增加、排序这样的功能,不要把 index 作为 key。

    事实上,写列表渲染时,永远不要把 index 做为 key,key 一定要是唯一标识。

    至于原因,就要理解 diff 算法之后才能明白了。

    待解答问题:

    别着急,立了个写100个 vue 问题相关文章的 flag 呢,后面的文章再慢慢分析。

    希望我的 vue 系列文章能对前端路上的你有帮助~

    【相关推荐:vue.js视频教程

    以上就是vue中为什么v-for指令的 key 值不能是 index?的详细内容,更多请关注php中文网其它相关文章!

    声明:本文转载于:掘金社区,如有侵犯,请联系admin@php.cn删除
    专题推荐:vue v-for key
    上一篇:【VuePress实战】手把手带你开发一个代码复制插件 下一篇:vue技术笔记之Vue技术栈(图文详解)

    相关文章推荐

    • 如何从0撸出一个Vue组件库并发布到npm• 快速了解Vue3中的Fragment、Suspense、Portal特性• vue中的ajax一般放在哪个生命周期中• 聊聊vue2.x中this的指向问题,它为什么指向vue实例?• Vue3中5个可以提高开发效率的小知识【整理分享】• 尤雨溪最新公布:Vue3将成为默认版本!

    全部评论我要评论

  • 取消发布评论发送
  • 1/1

    PHP中文网