We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
我们先根据真实DOM生成一颗virtual DOM,当virtual DOM某个节点的数据改变后会生成一个新的Vnode,然后Vnode和oldVnode作对比,发现有不一样的地方就直接修改在真实的DOM上,然后使oldVnode的值为Vnode。
virtual DOM
Vnode
oldVnode
diff的过程就是调用名为patch的函数,比较新旧节点,一边比较一边给真实的DOM打补丁。
patch
virtual DOM是将真实的DOM的数据抽取出来,以对象的形式模拟树形结构。比如dom是这样的:
<div> <p>123</p> </div>
对应的virtual DOM(伪代码):
var Vnode = { tag: 'div', children: [ { tag: 'p', text: '123' } ] };
(温馨提示:VNode和oldVNode都是对象,一定要记住)
VNode
oldVNode
在采取diff算法比较新旧节点的时候,比较只会在同层级进行, 不会跨层级比较,新旧节点各有两个头尾的指针StartIdx和EndIdx,如果设置了key,就会用key进行比较,在比较的过程中,指针会往中间靠,一旦StartIdx>EndIdx表明新旧节点至少有一个已经遍历完了,就会结束比较。
StartIdx
EndIdx
key
StartIdx>EndIdx
<div> <p>123</p> </div> <div> <span>456</span> </div>
上面的代码会分别比较同一层的两个div以及第二层的p和span,但是不会拿div和span作比较。
比较的几种情况
if (oldVnode === vnode)
if(oldVnode.text !== null && vnode.text !== null && oldVnode.text !== vnode.text)
Node.textContent = vnode.text
if( oldCh && ch && oldCh !== ch )
else if (ch)
createEle(vnode)
vnode.el
createEle
else if (oldCh)
设置key和不设置key的区别:
不设key,newCh和oldCh只会进行头尾两端的相互比较,设key后,除了头尾两端的比较外,还会从用key生成的对象oldKeyToIdx中 查找匹配的节点,所以为节点设置key可以更高效的利用dom
如我们希望可以在B和C之间加一个F,Diff算法默认执行起来是这样的:
即把C更新成F,D更新成C,E更新成D,最后再插入E,是不是很没有效率?
所以我们需要使用key来给每个节点做一个唯一标识,Diff算法就可以正确的识别此节点,找到正确的位置区插入新的节点。
所以一句话,key的作用主要是为了高效的更新虚拟DOM。另外vue中在使用相同标签名元素的过渡切换时,也会使用到key属性,其目的也是为了让vue可以区分它们,否则vue只会替换其内部属性而不会触发过渡效果。
const list = [ { id: 1, name: "Person1" }, { id: 2, name: "Person2" }, { id: 3, name: "Person3" }, { id:4, name:"Person4" } ];
此时,删除 “Person4” 是正常的,但是如果我删除 “Person2” 就会出现问题
删除前
删除后
这个时候,除了Person1之外,剩下的Person3、Person4,因为被发现与相应key的绑定关系有变化,所以被重新渲染,这会影响性能。 如果此时list的item是select的选项,其中Person3是选中的,这个时候Person2被删除了,用index作为key就会变成是 Person4选中的了,这就产生了bug。
Person1
Person3
Person4
list
item
select
Person2
index
如果使用唯一id作为key,删除Person2后,剩下的元素因为与key的关系没有发生变化,都不会被重新渲染,从而达到提升性能的目的。此时,list的item作为select的选项,也不会出现上面所描述的bug。数据库中每一条数据都会一个id作为唯一标识,而这个id也是我们最常使用作为key值来源。
id
The text was updated successfully, but these errors were encountered:
No branches or pull requests
一、当数据发生变化时,vue是怎么更新节点的?
我们先根据真实DOM生成一颗
virtual DOM
,当virtual DOM
某个节点的数据改变后会生成一个新的Vnode
,然后Vnode
和oldVnode
作对比,发现有不一样的地方就直接修改在真实的DOM上,然后使oldVnode
的值为Vnode
。diff的过程就是调用名为
patch
的函数,比较新旧节点,一边比较一边给真实的DOM打补丁。二、virtual DOM和真实DOM的区别?
virtual DOM是将真实的DOM的数据抽取出来,以对象的形式模拟树形结构。比如dom是这样的:
对应的virtual DOM(伪代码):
(温馨提示:
VNode
和oldVNode
都是对象,一定要记住)三、diff的比较方式?
在采取diff算法比较新旧节点的时候,比较只会在同层级进行, 不会跨层级比较,新旧节点各有两个头尾的指针
StartIdx
和EndIdx
,如果设置了key
,就会用key
进行比较,在比较的过程中,指针会往中间靠,一旦StartIdx>EndIdx
表明新旧节点至少有一个已经遍历完了,就会结束比较。上面的代码会分别比较同一层的两个div以及第二层的p和span,但是不会拿div和span作比较。
比较的几种情况
if (oldVnode === vnode)
,他们的引用一致,可以认为没有变化。if(oldVnode.text !== null && vnode.text !== null && oldVnode.text !== vnode.text)
,文本节点的比较,需要修改,则会调用Node.textContent = vnode.text
。if( oldCh && ch && oldCh !== ch )
, 两个节点都有子节点,而且它们不一样,这样我们会调用updateChildren函数比较子节点,这是diff的核心else if (ch)
,只有新的节点有子节点,调用createEle(vnode)
,vnode.el
已经引用了老的dom节点,createEle
函数会在老dom节点上添加子节点。else if (oldCh)
,新节点没有子节点,老节点有子节点,直接删除老节点。四、key的作用
设置key和不设置key的区别:
如我们希望可以在B和C之间加一个F,Diff算法默认执行起来是这样的:
即把C更新成F,D更新成C,E更新成D,最后再插入E,是不是很没有效率?
所以我们需要使用key来给每个节点做一个唯一标识,Diff算法就可以正确的识别此节点,找到正确的位置区插入新的节点。
所以一句话,key的作用主要是为了高效的更新虚拟DOM。另外vue中在使用相同标签名元素的过渡切换时,也会使用到key属性,其目的也是为了让vue可以区分它们,否则vue只会替换其内部属性而不会触发过渡效果。
五、为什么不能用index作为key?
此时,删除 “Person4” 是正常的,但是如果我删除 “Person2” 就会出现问题
删除前
删除后
这个时候,除了
Person1
之外,剩下的Person3
、Person4
,因为被发现与相应key
的绑定关系有变化,所以被重新渲染,这会影响性能。如果此时
list
的item
是select
的选项,其中Person3
是选中的,这个时候Person2
被删除了,用index
作为key
就会变成是Person4
选中的了,这就产生了bug。如果使用唯一
id
作为key
,删除Person2
后,剩下的元素因为与key
的关系没有发生变化,都不会被重新渲染,从而达到提升性能的目的。此时,list
的item
作为select
的选项,也不会出现上面所描述的bug。数据库中每一条数据都会一个id
作为唯一标识,而这个id
也是我们最常使用作为key
值来源。参考文献
The text was updated successfully, but these errors were encountered: