You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
function createKeyToOldIdx (children, beginIdx, endIdx) {
let i, key
const map = {}
for (i = beginIdx; i <= endIdx; ++i) {
key = children[i].key
if (isDef(key)) map[key] = i
}
return map
}
function findIdxInOld (node, oldCh, start, end) {
for (let i = start; i < end; i++) {
const c = oldCh[i]
if (isDef(c) && sameVnode(node, c)) return i
}
}
从前篇文章说起
前几天我写了一篇文章,sortable.js——Vue 数据更新问题 ,当时自己只是数据的强制刷新角度去分析,而且并没找到真正的“元凶”。
很感谢有人帮我指出,可能是
Vue
的key
值,导致数据渲染不正确的。由此,我做了进一步的尝试。key 的一个错误使用——使用
index
作为key
不知道你在写
v-for
的时候,会不会直接使用index
作为它的key
值,是的,我承认我会,不得不说,这真的不是一个好习惯。根据上篇文章,我们还是用
sortable.js
作为例子讨论。以下是核心代码,其中arrData
的值为 [1,2,3,4]当然一开始的时候,数据渲染肯定是没有问题的
好了,我们来看下以下的操作:
可以看到,我将3拖到2上面的时候,下面的数据变成了 1342,但是上面视图的还是1234。然后我第四位置拖到第三位置的时候,下面的数据也是生效的,但是上面的数据似乎全部错乱了。很好,我们重现了案发现场。
接着我改了绑定的
key
值,因为这里的例子比较特殊,我们就认为item
的值都不相同再看效果:
是的,这个时候数据就完全跟视图同步了。
为什么?
先看官方文档中
key
的一句介绍之所以会造成上面渲染错误的情况,是因为我们的
key
值不是独特的,比如上面的key
值,在调整数组顺序后就每一项原来的key
值都变了,所以导致了渲染错误。我们先来得出一个结论,用
index
作为key
值是有隐患的,除非你能保证index
始终能够能够作为一个唯一的标识key 值到底有什么用
在
vue2.0
之后,我们不写key
的话,就会报warning
,那也就是说官方是希望我们写key
值的,那么key
到底在vue
中扮演了什么样的角色?不使用 key 可以提高性能么
答案是,是的!可以!
先看官方解释:
比如现在有一个数组 [1,2,3,4]变成了[2,1,3,4],那么没有
key
的值会采取一种“就地更新策略”,见下图。它不会移动元素节点的位置,而是直接修改元素本身,这样就节省了一部分性能而对于有
key
值的元素,它的更新方式如下图所示。可以看到,这里它对 DOM 是移除/添加的操作,这是比较耗性能的。竟然不带
key
性能更优,为何还要带 key先来看一个例子,核心代码如下,这里模仿一个切换
tab
的功能,也就是切换的tab1 是1,2,3,4。tab2 是 5,6,7,8。其中有设置了一个点击设置第一项字体色为红色的功能。那么当我们点击tab1将字体色设置成红色之后,再切换到 tab2,我们预期的结果是我们第一项字体的初始颜色而不是红色,但是结果却还是红色。
这就超出了我们的预期了,也就是官方文档所说的,默认模式指的就是不带
key
的状态,对于依赖于子组件状态或者临时 DOM 状态的,这种模式是不适用的。我们来看带上
key
之后的效果这就是官方文档之所以推荐我们写
key
的原因,根据文档的介绍,如下:那么
Vue
底层key
值到底是怎么去做到以上的功能?我们就得聊聊diff
算法以及虚拟DOM
了。key 在 diff 算法中的作用
这里我们不谈
diff
算法的具体,只看key
值在其中的作用。(diff
算法有机会我们再聊)看
vue
源码中src/core/vdom/patch.js
我们整理一下代码块:
那么最主要还是
createKeyToOldIdx
和findIdxInOld
两个函数的比较,那么他们做了什么呢?我们可以看到,如果我们有
key
值,我们就可以直接在createKeyToOldIdx
方法中创建的map
对象中根据我们的key
值,直接找到相应的值。没有key
值,则需要遍历才能拿到。相比于遍历,映射的速度会更快。key
值是每一个vnode
的唯一标识,依靠key
,我们可以更快的拿到oldVnode
中相对应的节点。参考
第 1 题:写 React / Vue 项目时为什么要在列表组件中写 key,其作用是什么?
解析vue2.0的diff算法
欢迎大家关注我的前端大杂货铺~
The text was updated successfully, but these errors were encountered: