V-for循环key值的作用
在Vue中 v-for 正在更新已渲染过的元素列表是,它默认用“就地复用”策略。如果数据项的顺序被改变,Vue将不是移动DOM元素来匹配数据项的改变,而是简单复用此处每个元素,并且确保它在特定索引下显示已被渲染过的每个元素,key值类似于ID具有唯一性。
要解释key的作用,不得不先介绍一下虚拟DOM的Diff算法了。
vue的虚拟DOM的Diff算法,其核心是基于两个简单的假设:
- 两个相同的组件产生类似的DOM结构,不同的组件产生不同的DOM结构。
- 同一层级的一组节点,他们可以通过唯一的id进行区分。
基于以上这两点假设,使得虚拟DOM的Diff算法的复杂度从O(n^3)降到了O(n)
这里我们借用React’s diff algorithm中的一张图来简单说明一下:
Diff算法简析
-
当页面的数据发生变化时,Diff算法只会比较同一层级的节点。
-
如果节点类型不同,直接干掉前面的节点,再创建并插入新的节点,不会再比较这个节点的子节点了。
-
如果节点类型相同,则会重新设置该节点的属性,从而实现节点的更新。
我们往一个列表里面插入一条数据
Diff算法默认执行的是这样子
分析下整体流程:
-
比较A,A,相同类型的节点,进行patch,但数据相同,不发生dom操作
-
比较B,B,相同类型的节点,进行patch,但数据相同,不发生dom操作
-
比较C,F,相同类型的节点,进行patch,数据不同,发生dom操作
-
比较D,C,相同类型的节点,进行patch,数据不同,发生dom操作
-
比较E,D,相同类型的节点,进行patch,数据不同,发生dom操作
循环结束,将E插入到DOM中
一共发生了3次更新,1次插入操作
在使用key的情况:vue会进行这样的操作:
-
比较A,A,相同类型的节点,进行patch,但数据相同,不发生dom操作
-
比较B,B,相同类型的节点,进行patch,但数据相同,不发生dom操作
-
比较C,F,不相同类型的节点
-
比较E、E,相同类型的节点,进行patch,但数据相同,不发生dom操作
-
比较D、D,相同类型的节点,进行patch,但数据相同,不发生dom操作
-
比较C、C,相同类型的节点,进行patch,但数据相同,不发生dom操作
循环结束,将F插入到C之前
一共发生了0次更新,1次插入操作
通过上面两个小例子,可见设置key能够大大减少对页面的DOM操作,提高了diff效率