1.initMixin
- 把_init函数挂载到了原型上,每次new Vue或new VueComponent都会首先执行_init方法;
- Vue.prototype._init主要执行了以下的方法:
- 定义vm=this
- 设置Vue实例的唯一uid
- 把isVue设为true,防止vm被监听
- 如果this/vm是个组件,则initInternalComponent,否则合并Vue.options和vm.options,这个options将参与后面的其他initXXXX方法
- initLifecycle:建立实例的父子关系,以及根元素,将一些属性初始化
- initEvents:初始化绑定在组件上的事件,例如<selfdefineCom @myclick="myclick"/>
- initRender:设置外壳元素slots和attrs', '$listeners这两个属性为响应式
- **callHook(vm, 'beforeCreate');实例里定义的beforeCreate方法执行了,**所以在beforeCreated方法里是取不到data,method之类的值,因为定义这些的initState方法在后面
- initInjections:初始化Injections
- 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取的是私有变量_data
-
Object.defineProperty(Vue.prototype, '$data', dataDef)
-
定义props取的是私有变量_props
-
Object.defineProperty(Vue.prototype, '$props', propsDef);
-
注册原型方法delete Vue.prototype.delete = del;
-
注册原型方法unwatch .这里$watch创建的是个用户watcher
3.eventsMixin
- 定义once,off等方法毛病注册到Vue原型上
4.lifecycleMixin
定义_update,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源码的一个记录,如果有不妥当的地方,请各位帮忙指出,多多指教,谢谢你们。