总结Vue里面各种 initXXX 以及 XXXMixin 方法分别做了什么

207 阅读2分钟

1.initMixin

  • 把_init函数挂载到了原型上,每次new Vue或new VueComponent都会首先执行_init方法;
  • Vue.prototype._init主要执行了以下的方法:
  1. 定义vm=this
  2. 设置Vue实例的唯一uid
  3. 把isVue设为true,防止vm被监听
  4. 如果this/vm是个组件,则initInternalComponent,否则合并Vue.options和vm.options,这个options将参与后面的其他initXXXX方法
  5. initLifecycle:建立实例的父子关系,以及根元素,将一些属性初始化
  6. initEvents:初始化绑定在组件上的事件,例如<selfdefineCom @myclick="myclick"/>
  7. initRender:设置外壳元素vnode,设置vnode,设置slots和scopedSlots,设scopedSlots,设置'attrs', '$listeners这两个属性为响应式
  8. **callHook(vm, 'beforeCreate');实例里定义的beforeCreate方法执行了,**所以在beforeCreated方法里是取不到data,method之类的值,因为定义这些的initState方法在后面
  9. initInjections:初始化Injections
  10. initState:包括以下属性的初始化
  • initProps
  • initMethods
  • initData或observe(vm._data = {}, true /* asRootData */);
  • //上面的三个init只要是判断属性名不同以及把他们代理到vm实例上
  • initComputed
  • initWatch
  • initProvide:初始化provide属性
  • callHook(vm, 'created');实例里定义的created方法执行了vm.$mount(相当于执行了mountComponent )
  • 执行new Vue里面的render:h=>h(xxx)方法或者vm.$options.render = createEmptyVNode;
  • callHook(vm, 'beforeMount');实例里定义的beforeMount方法执行了****初始化一个渲染watcher,渲染watcher初始化是会执行一遍updateComponent方法(这个以后说,这个方法主要是根据 由模板解析的render方法创建vnode和根据vnode生成真实dom)
  • callHook(vm, 'mounted');实例里定义的mounted方法执行了

2.stateMixin

  • 定义data对象获取私有属性,this.data对象获取私有属性,this.data取的是私有变量_data

  • Object.defineProperty(Vue.prototype, '$data', dataDef)

  • 定义props对象获取私有属性,this.props对象获取私有属性,this.props取的是私有变量_props

  • Object.defineProperty(Vue.prototype, '$props', propsDef); 

  • 注册原型方法setset和delete Vue.prototype.set=set;Vue.prototype.set = set; Vue.prototype.delete = del; 

  • 注册原型方法watchwatch和unwatch .这里$watch创建的是个用户watcher

3.eventsMixin

  • 定义on,on,once,emit.emit.off等方法毛病注册到Vue原型上

4.lifecycleMixin

    定义_update,forceUpdate,forceUpdate,destroy等方法毛病注册到Vue原型上

  • forceUpdate的原理是该实例里的渲染watcher(_watcher)更新一遍

  • destroy的方法里主要执行了以下过程,           beforeDestroy钩子方法会执行 

         把渲染、计算、用户watcher依次teardown

         移除真实dom(通过vm.__patch__(vm._vnode, null)函数) 

        destroy钩子方法会执行 vm.$off();移除对所有事件的监听 

  •  _update主要是把虚拟Vnode通过patch方法变成真实dom,这个方法在_init方法里面的updateComponent会调用

           updateComponent = function () { vm._update(vm._render(), hydrating); }

5.renderMixin

  • installRenderHelpers,把下列方法注册到Vue原型上

  •   target._o = markOnce;
      target._n = toNumber;
      target._s = toString;
      target._l = renderList;
      target._t = renderSlot;
      target._q = looseEqual;
      target._i = looseIndexOf;
      target._m = renderStatic;
      target._f = resolveFilter;
      target._k = checkKeyCodes;
      target._b = bindObjectProps;
      target._v = createTextVNode;
      target._e = createEmptyVNode;
      target._u = resolveScopedSlots;
      target._g = bindObjectListeners;
      target._d = bindDynamicKeys;
      target._p = prependModifier;
    
  • 把$nextTick方法注册到Vue原型上

  • $nextTick主要是执行nextTick方法

  • 关于nextTick

    if (!pending) { //如果pending标志符为false的话,则可以执行 timerFunc(); pending = true; timerFunc();//这里面就是异步执行flushCallbacks的方法 }

    //flushCallbacks其实就是把一个栈里面的函数依次执行 //如果兼容promise,怎么用Promise.resolve().then(flushCallbacks) //否则如果兼容MutationObserver, var observer = new MutationObserver(flushCallbacks); //如果observe的对象发生改变,flushCallbacks执行//否则setImmediate(flushCallbacks); //最后上述三种都不兼容的话 setTimeout(flushCallbacks, 0); //isNative(xxx)是检查xxx函数是否为JavaScript运行时环境内建函数(浏览器中的支持情况) if (typeof Promise !== 'undefined' && isNative(Promise)) { var p = Promise.resolve(); timerFunc = function () { p.then(flushCallbacks); }; isUsingMicroTask = true; } else if (!isIE && typeof MutationObserver !== 'undefined' && ( isNative(MutationObserver) || MutationObserver.toString() === '[object MutationObserverConstructor]' )) { var counter = 1; var observer = new MutationObserver(flushCallbacks); var textNode = document.createTextNode(String(counter)); observer.observe(textNode, { characterData: true }); timerFunc = function () { counter = (counter + 1) % 2; textNode.data = String(counter); }; isUsingMicroTask = true; } else if (typeof setImmediate !== 'undefined' && isNative(setImmediate)) { timerFunc = function () { setImmediate(flushCallbacks); }; } else { timerFunc = function () { setTimeout(flushCallbacks, 0); }; }

  • _render

    //render是个函数,是有template预编译或者运行时编译获得的函数
    var ref = vm.$options;
    var render = ref.render; 
    //如果存在_parentVnode,则赋值给$vnode(_parentVnode是组件的外壳节点)
    vm.$vnode = _parentVnode;
    //执行上面的render函数,vm.__renderProxy其实就是vm加了规范校验(在非生产环境)
    //这里的vnde,tag是html元素,是按照组件模板的内容构建的
    //而vm.$vnode = _parentVnode;这个vnode的tag是组件的名称
    vnode = render.call(vm._renderProxy, vm.$createElement);
    //如果vnode不是Vnode的实例
     if (!(vnode instanceof VNode)) {
        vnode = createEmptyVNode();
    }
    vnode.parent = _parentVnode;//建立父子关系,父节点是外壳节点
    return vnode
    //这里生成的vnode会作为vm._update函数的参数
    //updateComponent = function () { vm._update(vm._render(), hydrating); }
    

      

这篇文章主要作为我学习vue源码的一个记录,如果有不妥当的地方,请各位帮忙指出,多多指教,谢谢你们。