生命周期
new Vue
export function initMixin(Vue) {
Vue.prototype._init = function(options) {
const vm = this;
vm.$options = mergeOptions(
resolveConstructorOptions(vm.constructor),
options || {},
vm
)
vm._selft = vm;
initLifecycle(vm); // 初始化声明周期
initEvents(vm); // 初始化事件
initRender(vm); // 初始化渲染
callHook(vm, 'beforeCreate'); // 调用beforeCreate hook
initInjections(vm); // 调用injections
initState(vm); // 初始化porps, methods, data, computed, watch
initProvide(vm); // 初始化provide
callHook(vm, 'created');
if(vm.$options.el) {
vm.$mount(vm.$options.el);
}
}
}
合并属性
合并options
vm.$options = (
resolveConstructorOptions(vm.constructor),
options || {},
vm
)
resolveConstructorOptions(vm.constructor)的返回值和传入的options合并,这里的resolveConstructorOptions其实就是解析出构造函数的options选项,这里传入vm.constructor所以得出的是Vue.options,下面是Vue.options的定义
src/core/global-api/index.js
export function initGloabAPI(Vue: GlobalAPI) {
Vue.options = Object.create(null);
ASSET_TYPES.forEach(type => {
Vue.options[`${type}s`] = Object.create(null)
})
extend(Vue.options.components, builtInComponents);
}
export const ASSET_TYPES = [
'componet',
'directive',
'filter'
]
extend 语句执行之后,所有的内置组件都被注册,所以我们不需要自己去注册这些组件
mergeOptions
src/core/util/options.js
export function mergeOptions (
parent: Object,
child: Object,
vm?: Component
): Object {
if(typeof child === 'function') {
child = child.options;
}
const extendsFrom = child.extends
if(extendsFrom) {
// 递归合并extends
parent = mergeOptions(parent, extendsFrom, vm);
}
if(child.mixins) {
for(let i = 0, l = child.mixins.length; i < 1; i++) {
// 递归合并mixins
parent = mergeOptions(parent, child.mixins[i], vm);
}
}
const options = {}
let key;
for(key in parent) {
mergeField(key);
}
for(key in child) {
if(!hasOwn(parent, key)) { // child特有的属性(parent中没有的)
mergeField(key);
}
}
function mergeField(key) {
// strat是strategy的缩写(策略模式),对于不同类型的数据有着不同的合并策略。
// 不同的合并策略由传入的key决定
// data watch props compputed......
const strat = strats[key] || defaultStrat;
options[key] = strat(parent[key], child[key], vm, key);
}
return options;
}
mergeField
Eg:合并hooks
function mergeHook(parentVal, childVal) : {
return childVal
? parentVal
? parentVal.concat(childVal)
: Array.isArray(child)
? child
: [child]
:parentVal
}
LIFECYCLE_HOOKS.forEach(hook => {
strats[hook] = mergeHook;
})
src/shared/constants.js
export const LIFECYCLE_HOOKS = [
'beforeCreate',
'created',
'beforeMount',
'mounted',
'beforeUpdate',
'updated',
'beforeDestroy',
'destroyed',
'activated',
'deactivated',
'errorCaptured'
]
由于Vue支持mixins模式,到达触发某个钩子函数的时候其实是需要触发多个函数的,所以需要用一个数组来保存。(发布-订阅模式)
上面的三元表达式的意思是:如果childVal存在,parentVal存在那么两者合并返回,如果childVal存在parentVal不存在,那么判断childVal是否是数组,如果是那么直接返回,如果不是那么加上数组包裹。如果childVal不存再那么直接返回parentVal
callHook函数触发
src/core/instance/lifecycle.js
// 发布过程
export function callHook(vm: Componet, hook: string) {
const handlers = vm.$options[hook];
if(handlers) {
for(let i = 0;m j = handlers.length; i < j; i++) {
try{
handlers[i].call(vm);
} catch(e) {
handleError(e, vm, `${hook} hook`);
}
}
}
}