diff 算法需要比对虚拟 dom 的修改,然后异步的渲染到页面中,当出现大量相同的标签时,vnode 会首先判断 key 和标签名是否一致,如果一致再去判断子节点一致,使用 key 可以帮助 diff 算法提升判断的速度,在页面重新渲染时更快消耗更少

 vue 中 key 值的作用可以分为两种情况来考虑。
 ​
 第一种情况是 v-if 中使用 key。由于 Vue 会尽可能高效地渲染元素,通常会复用已有元素而不是从头开始渲染。因此当我们使用 v-if 来实现元素切换的时候,如果切换前后含有相同类型的元素,那么这个元素就会被复用。如果是相同的 input 元素,那么切换前后用户的输入不会被清除掉,这样是不符合需求的。因此我们可以通过使用 key 来唯一的标识一个元素,这个情况下,使用 key 的元素不会被复用。这个时候 key 的作用是用来标识一个独立的元素。
 ​
 第二种情况是 v-for 中使用 key。用 v-for 更新已渲染过的元素列表时,它默认使用“就地复用”的策略。如果数据项的顺序发生了改变,Vue 不会移动 DOM 元素来匹配数据项的顺序,而是简单复用此处的每个元素。因此通过为每个列表项提供一个 key 值,来以便 Vue 跟踪元素的身份,从而高效的实现复用。这个时候 key 的作用是为了高效的更新渲染虚拟 DOM。
 ​
 key 是为 Vue 中 vnode 的唯一标记,通过这个 key,diff 操作可以更准确、更快速
 ​
 - 更准确:因为带 key 就不是就地复用了,在 sameNode 函数`a.key === b.key`对比中可以避免就地复用的情况。所以会更加准确。
 - 更快速:利用 key 的唯一性生成 map 对象来获取对应节点,比遍历方式更快

相关代码如下

 // 判断两个vnode的标签和key是否相同 如果相同 就可以认为是同一节点就地复用
 function isSameVnode(oldVnode, newVnode) {
   return oldVnode.tag === newVnode.tag && oldVnode.key === newVnode.key;
 }
 ​
 // 根据key来创建老的儿子的index映射表  类似 {'a':0,'b':1} 代表key为'a'的节点在第一个位置 key为'b'的节点在第二个位置
 function makeIndexByKey(children) {
   let map = {};
   children.forEach((item, index) => {
     map[item.key] = index;
   });
   return map;
 }
 // 生成的映射表
 let map = makeIndexByKey(oldCh);

diff 算法详解 传送门

详细资料可以参考: 《Vue 面试中,经常会被问到的面试题 Vue 知识点整理》 《Vue2.0 v-for 中 :key 到底有什么用?》 《vue 中 key 的作用》

为什么不建议用index作为key?

使用 index 作为 key和没写基本上没区别,因为不管数组的顺序怎么颠倒,index 都是 0, 1, 2…这样排列,导致 Vue 可能会复用错误的旧子节点,做很多额外的工作。

key 应为唯一标示,在数组变更时插入或删除后,index 无法确保始终指向对应的序列

更多推荐

vue 中的 key