vue3 Diff算法
patch
函数的核心就是Diff算法。
function patch (oldVnode, vnode, parentElm) {
if (!oldVnode) {
addVnodes(parentElm, null, vnode, 0, vnode.length - 1);
} else if (!vnode) {
removeVnodes(parentElm, oldVnode, 0, oldVnode.length - 1);
} else {
if (sameVnode(oldVNode, vnode)) {
patchVnode(oldVNode, vnode);
} else {
removeVnodes(parentElm, oldVnode, 0, oldVnode.length - 1);
addVnodes(parentElm, null, vnode, 0, vnode.length - 1);
}
}
}
patch
函数的功能主要是新旧VNode
节点,将差异更新到视图上,所以传入参数有新旧2个VNode
以及父节点element
,先捋清函数的主逻辑:
首先当旧节点oldVnode
不存在时,相当于新节点vnode
替代没有的节点,所以直接用addVnodes
将这些节点批量添加到parentElm
上面。
if (!oldVnode) {
addVnodes(parentElm, null, vnode, 0, vnode.length - 1);
}
同理,当新VNode节点vnode
不存在时,相当于把旧的节点删除,所以直接使用removeVnodes
函数进行批量的节点删除。
else if (!vnode) {
removeVnodes(parentElm, oldVnode, 0, oldVnode.length - 1);
}
最后一种情况,就是当旧节点oldVnode
和新节点vnode
同时存在的情况下,需要判断它们是否属于sameVnode
(相同的节点)。如果是则执行patchVnode
函数进行差异对比更新,否则删除旧节点,增加新节点。
if (sameVnode(oldVNode, vnode)) {
patchVnode(oldVNode, vnode);
} else {
removeVnodes(parentElm, oldVnode, 0, oldVnode.length - 1);
addVnodes(parentElm, null, vnode, 0, vnode.length - 1);
}
sameVnode
function sameVnode () {
return (
a.key === b.key &&
a.tag === b.tag &&
a.isComment === b.isComment &&
(!!a.data) === (!!b.data) &&
sameInputType(a, b)
)
}
function sameInputType (a, b) {
if (a.tag !== 'input') return true
let i
const typeA = (i = a.data) && (i = i.attrs) && i.type
const typeB = (i = b.data) && (i = i.attrs) && i.type
return typeA === typeB
}
sameVnode
其实很简单,只有当 key
、 tag
、 isComment
(是否为注释节点)、 data
同时定义(或不定义),同时满足当标签类型为 input
的时候 type
相同(某些浏览器不支持动态修改类型,所以他们被视为不同类型)即可。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。