Skip to content

Latest commit

 

History

History
88 lines (61 loc) · 4.27 KB

vdom概述.md

File metadata and controls

88 lines (61 loc) · 4.27 KB

之前我们讲解了把HTML模板字符串,解析成render函数的过程。从render函数,到真真切切把内容渲染到页面中,还需要经过哪些步骤呢?这就是我们接下来要说的内容。

我们都知道Vue2.0之后,引入了虚拟dom。那么虚拟dom到底是个什么东西呢?其实它就是一个有着一定数据结构的对象,因为我们原生创建一个dom对象时,会给它添加许许多多的属性。在控制台执行如下代码试试:

var div = document.createElement('div');
for(var k in div ){
  console.log(k)
}

我们看到,打印了几十个属性。当我们页面中dom数比较多的时候,频繁的修改、增加dom的数量,对性能会有极大的浪费。虚拟dom就是为了解决这个问题而生,它建立在真实的dom之上。当数据驱动dom修改时,它会通过diff计算,来尽量少的创建新元素,而尽可能多地复用旧的om,这样就可以减少频繁创建新dom带来的消耗。

其实调用render函数,返回的就是一个虚拟动dom——vnode。它很简单,就是保存了一些当前dom相关的数据,以及与其它vnode之间的父子关系等,具体结构见VNode

vnode如何绘制到页面上呢?我们回到Vue.prototype._update

Vue.prototype._update = function (vnode: VNode, hydrating?: boolean) {
    ...
    if (!prevVnode) {
      // initial render
      vm.$el = vm.__patch__(
        vm.$el, vnode, hydrating, false /* removeOnly */,
        vm.$options._parentElm,
        vm.$options._refElm
      )
    } else {
      // updates
      vm.$el = vm.__patch__(prevVnode, vnode)
    }
    ...
  }

别的暂且不管,我们看到这里有一个特别重要的方法vm.__patch__。这就是我们元素渲染、vnode做diff并修改、元素销毁的地方。

上面的代码中,prevVnode指的是旧的vnode,我们第一次创建时,没有旧的vnode,所以!prevVnode返回true,此时的操作就是创建根据vnode直接绘制dom到页面中。

当数据更新再次调用_update方法时,prevVnode是旧的vnode,此时传入新旧两个虚拟dom对象,__patch__会对它们做diff,并相应修改页面展现。

// 销毁对象同样是通过__patch__方法。
Vue.prototype.$destroy = function () {
    ...
    vm.__patch__(vm._vnode, null)
    ...
  }

从上面的代码我们看到销毁vue对象时,通过给__patch__第二个参数传入null,来从页面中删除相应dom。

该方法添加到Vue.prototype上是在src/entries/web-runtime.js中:

Vue.prototype.__patch__ = inBrowser ? patch : noop

我们看到,只有是在浏览器中,该方法是patch,否则,它是一个空函数。

文件开头有该方法引入的地方import { patch } from 'web/runtime/patch',其实该方法在src/platforms/web/runtime/patch.js

import * as nodeOps from 'web/runtime/node-ops'
import { createPatchFunction } from 'core/vdom/patch'
import baseModules from 'core/vdom/modules/index'
import platformModules from 'web/runtime/modules/index'

const modules = platformModules.concat(baseModules)

export const patch: Function = createPatchFunction({ nodeOps, modules })

这个文件夹下的内容,其实我们也比较熟悉,就是区分webweex不同内容的地方。

nodeOps 封装了许许多多对原生dom操作的方法,基本上都很简单,大家自己看一眼就好了。

modules 和之前编译html文本时类似,这里是对一些特殊内容的特殊处理,它内部提供了一组又一组的createupdatedestroy方法,在patch的不同时间分别调用。

baseModuleswebweex都有的处理,包括directivesref属性的处理。

platformModules 很明显就是平台相关的一些属性的处理,这里包括attrsclassdomPropsonstyleshow

其实这些属性对应的都是生成render字符串调用的generate函数中,给_c传入的第二个参数,也就是创建vnode时传入的一些属性。

具体的patch还是来自createPatchFunction,具体的操作都在这里,之后我会单独拿出来讲解,今天就是简单的带大家过一下。