1、更新过程
主要流程如下:
a、页面依赖属性变化,触发执行渲染Watch,渲染Watch执行updateComponent(Watcher.getter),执行render函数,获取更新后的Vnode;
b、比对新旧Vnode是否类似(sameVnode),同级节点进行比对,旧节点不存在则新增新节点;
b、新旧Vnode类似,则执行patchVnode,比对新旧Vnode的属性值;
c、如果存在子Vnode,则执行updateChildren,比对新旧Vnode子元素,最终也会执行patchVnode比对子元素。
2、更新时主要执行的源码
2.1 相似的Vnode节点判断条件
需要判断Vnode的key、tag标签、data等等属性,具体源码如下图:
2.2 相似的Vnode节点通过patchVnode更新
源码如下:
function patchVnode (
oldVnode,
vnode,
insertedVnodeQueue,
ownerArray,
index,
removeOnly
) {
if (oldVnode === vnode) {
return
}
if (isDef(vnode.elm) && isDef(ownerArray)) {
// clone reused vnode
vnode = ownerArray[index] = cloneVNode(vnode);
}
var elm = vnode.elm = oldVnode.elm;
if (isTrue(oldVnode.isAsyncPlaceholder)) {
if (isDef(vnode.asyncFactory.resolved)) {
hydrate(oldVnode.elm, vnode, insertedVnodeQueue);
} else {
vnode.isAsyncPlaceholder = true;
}
return
}
// reuse element for static trees.
// note we only do this if the vnode is cloned -
// if the new node is not cloned it means the render functions have been
// reset by the hot-reload-api and we need to do a proper re-render.
if (isTrue(vnode.isStatic) &&
isTrue(oldVnode.isStatic) &&
vnode.key === oldVnode.key &&
(isTrue(vnode.isCloned) || isTrue(vnode.isOnce))
) {
vnode.componentInstance = oldVnode.componentInstance;
return
}
var i;
var data = vnode.data;
if (isDef(data) && isDef(i = data.hook) && isDef(i = i.prepatch)) {
i(oldVnode, vnode);
}
var oldCh = oldVnode.children;
var ch = vnode.children;
if (isDef(data) && isPatchable(vnode)) {
for (i = 0; i < cbs.update.length; ++i) { cbs.update[i](oldVnode, vnode); }
if (isDef(i = data.hook) && isDef(i = i.update)) { i(oldVnode, vnode); }
}
if (isUndef(vnode.text)) {
if (isDef(oldCh) && isDef(ch)) {
if (oldCh !== ch) { updateChildren(elm, oldCh, ch, insertedVnodeQueue, removeOnly); }
} else if (isDef(ch)) {
if (process.env.NODE_ENV !== 'production') {
checkDuplicateKeys(ch);
}
if (isDef(oldVnode.text)) { nodeOps.setTextContent(elm, ''); }
addVnodes(elm, null, ch, 0, ch.length - 1, insertedVnodeQueue);
} else if (isDef(oldCh)) {
removeVnodes(oldCh, 0, oldCh.length - 1);
} else if (isDef(oldVnode.text)) {
nodeOps.setTextContent(elm, '');
}
} else if (oldVnode.text !== vnode.text) {
nodeOps.setTextContent(elm, vnode.text);
}
if (isDef(data)) {
if (isDef(i = data.hook) && isDef(i = i.postpatch)) { i(oldVnode, vnode); }
}
}
更新新旧Node属性的方法放在在cbs.update数组里,比对新旧节点的attrs、class、监听函数、props、style、和指令,
3、应用
之所以想弄清楚VUE更新原理,是为了优化一个大数据页面操作时卡顿的问题,当我们在主页面循环一个千条数据时,页面每修改一次属性都会触发一次更新,都需要比对这上千条数据Vnode,如果我们将这个大数量的部分放入一个组件中,仅仅只有大数据有变动才会发生更新,可以减少很多不要消耗内存的比对工作。
版权声明:本文为buler_sky原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。