本文正在参加「金石计划」
本文需要简单了解diff算法
对于key的使用,相信大多数人都知道,它可以提高组件复用率,在我的日常编码过程中,使用key的两大主要因素为:1.防止Eslint报错;2.强制刷新组件,防止复用
我潜意识一直认为key可以使得渲染加载更加迅速,但事实似乎并非如此
以下为个人的一些认识,如果有错误的地方希望大家帮忙指正
以下为判断新老虚拟dom节点是否为相同节点的函数
当key不存在时,判断的是标签tag,isComment:注释节点/文本节点
function sameVnode (a, b) {
return (
a.key === b.key &&
a.asyncFactory === b.asyncFactory && (
(
a.tag === b.tag &&
a.isComment === b.isComment &&
isDef(a.data) === isDef(b.data) && sameInputType(a, b)
) || (
isTrue(a.isAsyncPlaceholder) && isUndef(b.asyncFactory.error)
)
)
)
}
误区1:认为复用组件效率更高
例:当updateChildren指针指向节点比对时,当指针指向A,B两个节点时,假设A,B同标签但是内容不同,B为位置调到前面的节点。
1.无key时,sameVnode判断为true,进入patchVnode继续比对子节点
a.若无children只有innertext直接改变innertext
b.若有children继续下一步比对
2.有key时,saveVnode判断为false,进入前后两指针的以及经过查找发现在老的dom中发现B节点,需要将其位置调到前面
最初以为的操作:位置调动
实际的操作:源码位置
这里改变了真实的dom
误区2: 在updateChildren中使用了keyMap.has(Key),使用map映射来查找匹配节点,而非遍历,所以速度更快
在标签不同且key值不存在的情况下,确实是遍历要花费更多时间,但是对于一般标签相同的情况,sameVnode判断为true,大部分情况不会进入四个指针匹配不到而遍历查找这种情况。
所以综上所述,使用key的效率并不会更高,而为什么要使用key呢?vue官方给出的说明是这个
预期:number | string | boolean (2.4.2 新增) | symbol (2.5.12 新增)
key 的特殊 attribute 主要用在 Vue 的虚拟 DOM 算法,在新旧 nodes 对比时辨识 VNodes。如果不使用 key,Vue 会使用一种最大限度减少动态元素并且尽可能的尝试就地修改/复用相同类型元素的算法。而使用 key 时,它会基于 key 的变化重新排列元素顺序,并且会移除 key 不存在的元素。
有相同父元素的子元素必须有独特的 key。重复的 key 会造成渲染错误。
最常见的用例是结合 v-for:
它也可以用于强制替换元素/组件而不是重复使用它。当你遇到如下场景时它可能会很有用:
完整地触发组件的生命周期钩子 触发过渡 例如:
<transition> <span :key="text">{{ text }}</span> </transition>
当 text 发生改变时, 总是会被替换而不是被修改,因此会触发过渡。
推荐大家去看这个issue: 第 1 题:写 React / Vue 项目时为什么要在列表组件中写 key,其作用是什么?