美文网首页
Vue源码实现--VNode与挂载

Vue源码实现--VNode与挂载

作者: 勤奋的大鱼 | 来源:发表于2018-05-27 16:31 被阅读0次

     上一篇讲到当与页面渲染相关的依赖发生变化时,就会触发render watcher的run方法执行,重新收集依赖,而render watcher是把updateComponent方法作为watcher的getter,因此每次页面渲染所需的数据发生改变时,都会执行updateComponent方法。
    updateComponent方法很简单

    updateComponent = function () {
       vm._update(vm._render())
    }
    

    vm._render方法上一篇已经说过了,返回的是一个根据render函数生成的vnode对象,这里主要看一下vm._update以及相关的方法。

    Vue.prototype._update = function (vnode) {
      var vm = this
      var prevVnode = vm._vnode
      vm._vnode = vnode
      if (!prevVnode) { // 首次渲染
        vm.$el = this.__patch__(vm.$el, vnode)
      } else {
        vm.$el = this.__patch__(prevVnode, vnode)
      }
    }
    // 挂载、更新vnode到页面上
    Vue.prototype.__patch__ = function (oldVnode, vnode, parentElm, refElm) {
      var isRealElement = oldVnode.nodeType
      if (!isRealElement && sameVnode(oldVnode, vnode)) {
        patchVnode(oldVnode, vnode)
      } else {
        // 若isRealElement为true,说明传入的oldVnode为真实的dom节点,则生成一个空vnode实例,其中vnode.elm为传入的dom
        if (isRealElement) {
          oldVnode = emptyNodeAt(oldVnode)
        }
        var oldElm = oldVnode.elm
        var parentElm = nodeOps.parentNode(oldElm)
        createElm(vnode, parentElm, nodeOps.nextSibling(oldElm))
        // 移除老的dom元素
        removeVnodes(parentElm, [oldVnode], 0, 0)
      }
    }
    // 创建真实dom,refElm为插入在哪个元素之前
    function createElm (vnode, parentElm, refElm) {
      var data = vnode.data
      // 创建节点
      if (vnode.tag) {
        vnode.elm = nodeOps.createElement(vnode.tag)
        // 创建子节点
        createChildren(vnode, vnode.children)
        // 添加attr
        if (data) {
          updateAttrs(emptyNode, vnode)
        }
        // 插入到文档中
        insert(parentElm, vnode.elm, refElm)
      } else {
        vnode.elm = nodeOps.createTextNode(vnode.text)
        insert(parentElm, vnode.elm, refElm)
      }
    }
    

    大概逻辑是这样的:
    1.根据vm实例上是否有_vnode属性判断是否是首次渲染,若是首次渲染,则传给patch方法的是要被挂载到的dom元素,以及当前的vnode。
    2.在patch方法中,若传入的oldVnode是一个真实的dom,则为这个dom元素生成一个vnode对象(vnode.elm传入的dom节点),接下来的处理和新旧两个vnode不是同一个vnode的情况相同,插入新的vnode到文档中,并且删除旧的vnode。
    附上本文详细的代码注释与demo(相关代码

    相关文章

      网友评论

          本文标题:Vue源码实现--VNode与挂载

          本文链接:https://www.haomeiwen.com/subject/ghrzhftx.html