VUE更新原理

本文深入解析Vue.js中虚拟DOM更新的全过程,包括渲染Watch的工作原理、Vnode的更新流程及相似Vnode的判断条件,同时提供了优化大数据页面加载速度的具体方案。

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,如果我们将这个大数量的部分放入一个组件中,仅仅只有大数据有变动才会发生更新,可以减少很多不要消耗内存的比对工作。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值