1. vue
(function (global, factory) { //根据当前环境中用的ADM或COMMONJS格式的模块规范或者未用模块管理规范,将Vue(函数)对象返回给对应变量属性(或全局变量), typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : typeof define === 'function' && define.amd ? define(factory) : (global.Vue = factory()); }(this, (function () { 'use strict'; ..... return Vue$3; }) ));
1.立即执行函数
(function(global,factory){
}(this,(...)) )
将this和vue的构建函数传入匿名函数,根据当前环境进行vue初始化,如果是ADM模块管理下则传入define函数,Commonjs模块管理输出vue函数给module.exports,否则直接挂在全局变量上。
2.factory()
初始化Vue框架。
2.1 cached(fn)
cached(fn):缓存函数,提供fn缓存处理函数,然后存在内部变量cache中。
2.2 资源类型
//资源类型 var ASSET_TYPES = [ 'component',//组件 'directive',//指令 'filter'//过滤器 ]; //生命周期内的函数钩子 var LIFECYCLE_HOOKS = [ 'beforeCreate', 'created', 'beforeMount', 'mounted', 'beforeUpdate', 'updated', 'beforeDestroy', 'destroyed', 'activated', 'deactivated', 'errorCaptured' ];
2.3 合并strats
mergeHook合并LIFECYCLE_HOOKS钩子策略,将父级和子级的钩子函数和props属性合并为数组。
mergeAssets当存在一个虚拟节点(实例创建),我们需要将构造函数选项和实例选项和父级选项三方式合并。 AssetsType:组件、指令、过滤器
strats.watch:一个观察者哈希值不应该覆盖另一个观察者的哈希值,所以我们将它们合并为数组。
其他策略哈希:strats.props ,strats.methods ,strats.inject,strats.computed
2.4 全局消息通达
微任务、宏任务触发函数初始化。构建任务
宏任务macroTimerFunc:异步调用flushCallbacks回调函数列表中的函数:setImmediate或MessageChannel或setTimeout。
微任务microTimerFunc:如果有Promise.then则使用这个构建微任务,否则微任务实际执行宏任务。
2.5初始化渲染代理initProxy
1 //has代理处理对象 2 var hasHandler = { 3 has: function has (target, key) { 4 var has = key in target; 5 var isAllowed = allowedGlobals(key) || key.charAt(0) === '_'; 6 if (!has && !isAllowed) { 7 warnNonPresent(target, key); 8 } 9 //key不能是全局变量(或属性)也不能是_打头的‘私有’属性 10 return has || !isAllowed 11 } 12 }; 13 //get代理处理对象 14 var getHandler = { 15 get: function get (target, key) { 16 if (typeof key === 'string' && !(key in target)) { 17 warnNonPresent(target, key); 18 } 19 return target[key] 20 } 21 }; 22 // 23 initProxy = function initProxy (vm) { 24 if (hasProxy) {//如果()环境内置proxy代理 25 // determine which proxy handler to use 26 var options = vm.$options; //_withStripped 被卸载?待完善 27 //渲染代理定义,如果vm对象定义中有render等则用get代理处理函数否则使用has代理处理函数 28 var handlers = options.render && options.render._withStripped 29 ? getHandler 30 : hasHandler; 31 vm._renderProxy = new Proxy(vm, handlers); 32 } else { 33 vm._renderProxy = vm; 34 } 35 }; 36 37 38 ........ 39 40 Vue.prototype._render = function () { 41 42 ..... 43 vnode = render.call(vm._renderProxy, vm.$createElement); 44 .... 45 }
this就是vm._renderProxy渲染代理,生成html代码时需要读取数据,代理会过滤非枚举的属性对象。返回 target[key]时,又会触发Object.definePropery拦截。
2.6 设置渲染帮助函数
installRenderHelpers
2.8初始化混合
initMixin(Vue$3);
设置 Vue.prototype._init 全局初始化函数
2.9状态混合
stateMixin(Vue$3);
设置$data、$props 只读属性,分别来自_data 、_props。定义全局方法$set、$delete、$watch(用户使用的侦听方法)。
2.10 事件混合
eventsMixin(Vue$3);
在Vue原型上定义$on、$off、$once、$emit事件处理函数。
$on时将event设置到_events上维护,vm._events[event]。
2.11 生命周期混合
lifecycleMixin(Vue$3);
原型上定义_update、$forceUpdate、$destroy、
2.12渲染混合
renderMixin(Vue$3);
首先installRenderHelpers调用渲染辅助函数,定义$nextTick、_render、
2.13初始化全局api
initGlobalAPI:config、 Vue.util 、Vue.set、Vue.delete、Vue.nextTick 、Vue.options、Vue.options.components
2.13.1 初始化用户插件使用函数
initUse(Vue);
Vue.use 初始化插件,plugin.install,加载到Vue上。
2.13.2 初始化混合
initMixin$1(Vue);
Vue.mixin用户混合选项options
2.13.3 初始化扩展
initExtend(Vue); 子组件继承
2.13.4 初始化资源注册
initAssetRegisters(Vue);
3.
以上是vue自身初始化,下面用户使用vue
new Vue
生命周期函数:
mergeOptions:合并实例的components、directives、filters等属性。
initProxy: vm._renderProxy = new Proxy(vm, handlers);如果vm vue实例是带render的组件实例则添加gethandler处理函数,否则添加hashandler
beforecreate之前:初始化vue实例代理、初始化化声明周期,初始化事件,初始化渲染
created之前:初始化注入、初始化state状态(data/props)、初始化provide
function Vue$3 (options) { if ("development" !== 'production' && !(this instanceof Vue$3) ) { warn('Vue is a constructor and should be called with the `new` keyword'); } this._init(options); }
1.vm._uid
Vue节点的uid唯一编号设置,并给特殊的Vue节点设置_isVue标记,避免被监听。
1.1初始化内部组件或者合并参数选项
initInternalComponent(vm, options); : 如果options参数中表明是一个组件则初始化内部组件。优化内部组件实例化,因为动态选项合并很慢,并且内部组件选项都不需要特殊处理。
vm.constructor.options主要由之前VUE自执行时初始化的内容:components组件、directives指令、filters过滤。
resolveConstructorOptions :如果没有super父级继承属性,则直接返回上面三个属性(另_base)
mergeOptions (parent,child,vm) 然后将父级选项和子级选项合并,
首先检查child.components(如果child下还有组件的话)中的组件名称是否有效,无效则会给出提示信息或根据配置提示函数做处理。
1.1.1 规范化属性
normalizeProps(child, vm); 驼峰化属性名称
normalizeInject(child, vm); 规范化注入属性对象options.inject
normalizeDirectives(child);规范化指令,如果指令对象的某个属性值是函数则将该属性绑定到一个对象{ bind: def, update: def },其中def就是原指令函数。
child.extends 将子组件中的选项内容合并到父组件上去。
child.mixins Mixin 钩子与组件自身钩子同名时,Mixin 钩子按照传入顺序依次调用,并在调用组件自身的钩子之前被调用。
mergeField ()根据默认初始的components、directives、filters、_base(Vue$3)四个选项属性的各自策略将parent和child响应的属性合并
然后再将子组件中含有的属性和父组件中没有的属性合并到父组件(第一次newVue的时候的父级是之前加载vue就执行产生的默认四个选项的属性对象)中。
1.2 initProxy
vm._renderProxy = new Proxy(vm, handlers);如果vm vue实例是带render的组件实例则添加gethandler处理函数,否则添加hashandler。比如new Vue直接传el而不是手动添加render函数则对vue实例加_renderProxy 代理。
1.3 initLifecycle(vm);
找到vm父节点并将该vue实例存入父节点的children中。
vm节点挂父节点、根节点 vm.$parent = parent;
初始化children节点
$refs相关参数、_watcher、_inactive、相关标记:_directInactive、_isMounted标记、_isDestroyed、_isBeingDestroyed
1.4 initEvents(vm)
根据 listeners = vm.$options._parentListeners;添加组件更新监听器,
Vue.prototype.$on : 将事件处理函数挂在vm._events的事件对象上 (vm._events[event] || (vm._events[event] = [])).push(fn);
1.5 initRender(vm);
初始与渲染相关的属性_vnode、 _staticTrees、解析$slots插槽、$scopedSlots
vm._c :封装了createElement 创建元素关键函数,主要是内部使用
vm.$createElement:也封装了vm.$createElement函数,可供外部调用
defineReactive:添加对$attrs 和$listeners 属性对象 建立双向绑定
回调beforecreate钩子
callHook(vm, 'beforeCreate');
2. create部分
2.1initInjections(vm);
初始化注入:
2.2 initState(vm);
初始组件的 vm._watchers 监听器,props、methods、data、computed、watch
initData (vm):
mergedInstanceDataFn 合并数据对象函数,对data添加代理 proxy(vm, "_data", key);,key的来源是vm.$options.data;的data的关键字, proxy在vm对象上对获取_data上的key属性进行属性代理劫持,将key直接挂在vue实例的第一层,如果调用vm.key时,从target的_data的对应key上获取。
observe(data, true /* asRootData */);为options中的data,尝试给一个value值创建观察者实例,如果成功观察,返回新的观察者,如果值已经有一个观察者,则返回现有的观察者。
initProvide(vm);
以上 callHook(vm, 'created'); 回调created事件。
3. 装载el节点
vm.$mount(vm.$options.el);
Vue$3.prototype.$mount
将 template/el 转换成 render function,如果是el,则使用 template = getOuterHTML(el);获取html模板,
createCompileToFunctionFn 解析模板
var compiled = compile(template, options);将模板解析为一个对象,
res.render = createFunction(compiled.render, fnGenErrors);
v-show :调用toggleDisplay