使用v-for时为什么不能用index作为key值

1、Vue渲染数据的策略

Vue 默认按照“就地更新”的策略来更新通过 v-for 渲染的元素列表。当数据项的顺序改变时,Vue 不会随之移动 DOM 元素的顺序,而是就地更新每个元素,确保它们在原本指定的索引位置上渲染。

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

2、虚拟DMO的 diff 算法

diff算法采用同级比较。

        1、tag 标签不一致直接新节点替换旧节点。

        2、tag 标签一样。

                先替换属性

                对比子元素

                1.新老都有子元素,采用双指针方式进行对比

                sameVnode 判断tag和key完全相同为同一节点,进行节点复用

                             头和头相等对比

                             尾和尾相等对比

                             头和尾相等对比

                             sameVnode 的时候传入两个新老子节点patch(oldChild,newChild)

                乱序情况 -- 上面的都不符合,先遍历旧子节点数组形成 key值映射的map对象。

                然后根据新子节点数组循环 按照key值和位置关系移动以及新增节点 最后删除多余的旧子节点 如果移动旧节点同样需要patch(oldChild,newChild)

                2.新的有子元素,老的没有子元素。-- 直接将子元素虚拟节点转化成真实节点插入即可。

                3.新的没有子元素,老的有子元素。 -- 直接清空 innerHtml

3、无 tag 标签 -- 文本节点直接比较内容是否一致

3、为什么要用key

在没有 key 的情况下,Vue 将使用一种最小化元素移动的算法,并尽可能地就地更新/复用相同类型的元素。如果传了 key,则将根据 key 的变化顺序来重新排列元素,并且将始终移除/销毁 key 已经不存在的元素。

同一个父元素下的子元素必须具有唯一的 key。重复的 key 将会导致渲染异常。 

例如:有元素 A B C D E ,当我想把元素变成 B C D E 时

没有key值时,key默认都是undefined,就会按照diff算法的就地复用来进行比较,它会把A更新成B,B更新成C,C更新成D,最后删除E

有唯一的key值时,B C D E全部复用,只删除A

明显可以看出,当没有key值时改变元素会产生许多DOM操作,而DOM操作是非常消耗性能的,尤其是当有多层嵌套时,消耗的性能可想而知。

4、什么情况下使用index作为key值会出问题

在我们实际使用中使用index作为key或者不写key值,看起来除了操作DOM更耗性能,好像没有出现什么问题。

当你的只是用来做数据展示的时候,确实是没有什么问题的,但当你的子元素包含输入文本时就会出现问题了。

DEMO






此时我生成了三条数据

使用v-for时为什么不能用index作为key值_第1张图片

 当我点击删除第二条数据时,可以看到文本框的内容还是原本的第二条数据的内容

使用v-for时为什么不能用index作为key值_第2张图片

原因是虚拟DOM在比较元素的时候,因为DOM上的key等属性均未发生变化,所以其自身和内部的input均被复用了。

所以我们应该养成好习惯,不在实际开发过程中把index作为key值。

你可能感兴趣的:(Vue,vue.js,前端)