05/27
2016

##目录:

  1. Vue1主要类图
  2. Vue1生命周期
  3. Vue1的疑问与解答
  4. Vue2生命周期
  5. Vue2的疑问与解答

###1. Vue1主要类图 classStature

如上图:Vue1的结构中主要有4个类,

  1. Vue/VueComponent:创建Vue实例的类
  2. Dep:为所有要被监测的数据(data、props等)包括他们的属性、递归地建立getter、setter,并分别创建一个Dep与一堆getter、setter相关。当某一个数据的setter被触发,对应Dep对象的所有subscribers(Watcher实例)都会update。
  3. Directive:数据帮顶、指令的主要实现,数据绑定也被转化为Directive;Directive主要是关联Dom-Node与数据,当Directive.update被调用,也就对Dom-Node进行更新操作;在创建Directive的时候,会创建一个Watcher去监听与该Directive-expressoin相关联的数据的Dep;
  4. Watcher:真正去监听Dep的对象。该对象负责解析expression与数据-Dep之间的关系,并去监听(subcribe)相关数据的Dep。

###2. Vue1生命周期 lifecycleStracture

  1. Watcher与Dep的对应关系:每一个Dep对应一个属性的getter、setter,而Directive会创建一Watcher加入到该Directive依赖的所有属性的Dep对象的监听者中。当属性更改时,会通知[Watcher]进行更新(即Directive的更新)。
  2. Dep与Watcher监听关系的建立:在Directive创建Watcher的时候,Directive会有一个expression表达式,此时会先Dep.target赋值当前Watcher,并尝试计算一次该expression(即一次gettter.call操作);那么计算expression的时候,里面所依赖的属性们都会触发一次getter操作,同时在属性的getter中会判断Dep.target有没有值,如果有值(Watcher),则将该Watcher加入到自己Dep的监听者中;expression计算结束之后,Dep.target=null。(这里有一个bug:如果一个expression过于复杂,有条件判断,则有些属性有可能触发不了getter操作,那么就没法监听该属性。不过没问题,如果某些属性没使用,表示其他属性的值使得这些属性无效,要让这些属性有效,必要更改其他属性,更改其他属性的时候,该expression的getter重新触发,deps就会有所更新)。
  3. 通过expression解析获得该Watcher的getter、setter的时候会有一个expressionCache。以便表达式相同,重复利用。(在计算getter的时候会传入scope,不用担心不同scope相同expression的情况)。
  4. Directive多数对应一个Watcher,Watcher与Dep多对多。
  5. 创建VueComponent,第一步MyComponent=Vue.extend({}),创建的是类;第二步myComponent=new MyComponent(),创建一个实例,触发(init、created);第三步myComponent.$mount(el),挂载到dom上,触发ready

     var MyComponent = Vue.extend({
       template: '<div>Hello!</div>'
     })
    
     // 创建并挂载到 #app (会替换 #app)
     new MyComponent().$mount('#app')
    
     // 同上
     new MyComponent({ el: '#app' })
    
     // 手动挂载
     new MyComponent().$mount().$appendTo('#container')
    
  6. vm._callhook(‘ready’),触发的方法不仅仅包含vm._events[‘ready’]下面的方法,还有vm[‘ready’]方法。

###3. Vue1的疑问与解答

  1. ready触发的时机?插入到dom or fragment

    触发机制可以从图里看到;

    对于Component Directive而言,此时会生成一个空的占位TextNode替换ComponentElement所在的位置。而ComponentElement则作为options.el传递给VueComponnent的构造参数。VueComponent-1实例在compile阶段,会把元素的template插入到fragmentDocument中,若replace=true,VueComponent-1.$el=fragementDocument。若replace=falseVueComponent-1.$el=ComponentElement.appendChild(fragmentElement),在Directive的update阶段调用VueComponent-1.$before(TextNode)插入到页面之中。

  2. 更新dom的机制。

    几乎所有的directive都与node绑定(排除props),即使是TextNode,当directive的watcher监测到数据变化话,会触发Directive.update,对node进行dom操作,更新dom。

  3. componentDirective的依赖expOrFn是?

    expOrFn是child-test,componentDirective不创建watcher,传入的literal是true。

  4. prop Director: dep是recurcively?

    yes defineReactive 是recurcively

###4. Vue2生命周期 vue2-lifecycle

  1. Vue2中最大的不同就是各种api不在是vm的原型方法,从compile过程(template->vnode-render函数:ast->vnode)以及render过程(vnode->element)都是纯粹的api。这样的好处就是在web-render以及server-render可以共享代码。(注意这里面有些混淆:compile中的vnode-render函数是compile最终的结果,该render函数是用来生成vnode的;而render过程是将vnode转换成html的过程。)(代码名字起的不太好。)
  2. Vue2中的更新监测是对一个Vue/VueComponent实例的整体监测。每当一个数据更新,触发Dep->Watcher,整个Vue/VueComponent实例会重新走render过程,生成vnode,最后进行比较更新。
  3. 关于代码中directivesmodules的关系。directivesmodules都是处理html上可能出现的各种属性/指令的。最开始web/runtime/directives下面的所有指令都绑定在Vue.options.directives上。在vm._update/__patch__的时候,此时的modules(即cbs)(vdom/modules[directive,ref]web/runtime/mudules[events,class,style,props,attrs,transitions])会用hook:create来设置vnode/vnode.elm,而其中vdom/modules/directive指令处理的就是从compile/parse阶段传过来的rumtime的指令(web/runtime/directives[model,show],这些runtime的指令可以从vnode.context.$options.directives中获取引用)(方法对应:create-bind,update-update,postpatch-postupdate,destroy-unbind)。好了,设置完成了,好绕!!!
  4. 关于vnode的更新:在patchVnode的时候,会调用所有上一步的modules即cbshook:update(oldVnode, vnode);

###5. Vue2的疑问与解答

  1. lifecycle的不同:vue2中暂时没有ready,替代的是mounted
  2. server-render是怎么的一个实现?

    server-render的目的:进行seo优化,利用现有的vue代码,在服务端临时渲染出纯内容,返回给前端,进行seo优化

    vue-ssr的实现是:server-render独立实现了一套从vnode生成html的render过程。所以在使用server-render之前一定要自已调用compile过程,将template转成射给你陈工vnode的vnode-render函数。server-render最终结果只是生成纯粹的html内容。在页面初始化的时候也会被web-render给覆盖掉。

  3. vdom:https://github.com/paldepind/snabbdom
  4. html parser : http://erik.eae.net/simplehtmlparser/simplehtmlparser.js
  5. 关于vnode.ele(dom-elment对象)的属性:只有第一次用vnode去初始化页面的时候才会走createElement的流程,也只有第一次才会有这个属性,其他时间段ele为空
  6. vdom的计算和更新时每次一个setter触发都会执行一次的吗?

    不是,vue2里面有两层, 第一层:dom依赖的一些Dep(computed, getter)没有发生变更,就不会引起vdom的计算;若是发生了变更,还有第二层 第二层:vue2里面有一个shedule,每一个tick一个周期更新vdom,这是一个throttle的逻辑。

作者:teazean 文章地址: