从Vue3源码中分析key的作用
在文档中说到:
- key 的特殊 attribute 主要用在 Vue 的
虚拟 DOM 算法
,在新旧 nodes 对比时辨识VNodes
。 - 如果不使用 key,Vue 会使用一种最大限度减少动态元素并且尽可能的尝试就地
修改/复用相同类型元素
的算法。 - 而使用 key 时,它会基于 key 的变化
重新排列元素顺序
,并且会移除/销毁 key
不存在的元素。
在分析之前需要简单了解俩个概念 Vnode 和 虚拟 DOM
需要了解的俩个概念
Vnode
Vnode 全称为 Virtual Node, 即 虚拟节点 ,而它的本质就是一个 JS 对象
以代码为例:
1 |
|
// vue 会把 模板中的内容 转换为 vNode(对象)
1 |
|
虚拟 DOM
文档中说到:
- 虚拟 DOM 是轻量级的 JavaScript 对象,由渲染函数创建。
- 它包含三个参数:元素,具有数据、prop、attr 等的对象,以及一个数组。
- 数组是我们传递子级的地方,子级也具有所有这些参数,然后它们也可以具有子级,依此类推,直到我们构建完整的元素树为止。
以代码为例:
1 |
|
// 转换为虚拟 DOM
插入内容的案例
先看一个案例:当我们点击按钮时会插入一个数字 5 进去:
在整个过程中,我们可以确定的是 vue 在内部这次更新对于 ul 和 button 是不需要进行更新,需要更新的是 li 的列表。
在 Vue 中,对于相同父元素的子元素节点并不会重新渲染整个列表;因为对于列表中 1、2、3、4 它们都是没有变化的。在操作真实 DOM 的时候,我们只需要在中间插入一个 5 的 li 即可。
那么 Vue 中对于列表的更新究竟是如何操作的呢?
Vue 事实上会对于有 key 和没有 key 会调用两个不同的方法:
- 有 key,那么就使用
patchKeyedChildren
方法; - 没有 key,那么久使用
patchUnkeyedChildren
方法;
Vue3 源码对于 Key 的判断
没有 key 的操作情况下,vue 源码的做法
在没有 key 的情况下,vue3 源码是通过 patchUnkeyedChildren
方法来实现的
具体实现如图下:
第一步:遍历循环通过 patch 方法来做比较
第二步和第三步:判断新旧 nodes 的长度来进行对节点的删除或者新增
在有 key 的情况下,vue 源码的做法
有 key 的情况下,vue 对其操作有点复杂,可分为 5 个步骤。
具体如下图所示:
第一步:
第二步:
第三步:
第四步:
第五步:
总结
我们可以发现,Vue 在进行 diff 算法的时候,会尽量利用我们的 key 来进行优化操作,所有在没有 key 的情况下我们的效率是非常低的。 在进行插入或者重置排序的时候,保持相同的 key 可以让 diff 算法更加高效。