定义全局 Mixin 函数
// src/global-api/mixin.js
import {mergeOptions} from '../util/index'
//初始化mixin方法,即往Vue上挂载minxin方法,核心是mergeOptions
export default function initMixin(Vue){
Vue.mixin = function (mixin) {
// 合并对象
this.options=mergeOptions(this.options,mixin)
};
}
};
进行初始化操作
// src/index.js
import { initMixin } from "./init.js";
// Vue就是一个构造函数 通过new关键字进行实例化
function Vue(options) {
// 这里开始进行Vue初始化工作
this._init(options);
}
// 此做法有利于代码分割
initMixin(Vue);
export default Vue;
mergeOptions
- 对于钩子函数,Vue.mixin钩子会和Vue实例钩子进行合并(合并为一个数组,并且mixin的钩子排前,实例钩子排后);对于非钩子函数,Vue.mixin字段会被Vue实例字段替换掉(实例有这个字段就替换,没有就不替换);
// src/util/index.js
// 定义生命周期
export const LIFECYCLE_HOOKS = [
"beforeCreate",
"created",
"beforeMount",
"mounted",
"beforeUpdate",
"updated",
"beforeDestroy",
"destroyed",
];
// 合并策略
const strats = {};
//生命周期合并策略
function mergeHook(parentVal, childVal) {
// 如果有儿子
if (childVal) {
if (parentVal) {
// 合并成一个数组
return parentVal.concat(childVal);
} else {
// 包装成一个数组
return [childVal];
}
} else {
return parentVal;
}
}
// 为生命周期添加合并方法
LIFECYCLE_HOOKS.forEach((hook) => {
strats[hook] = mergeHook;
});
// mixin核心方法,进行合并
export function mergeOptions(parent, child) {
const options = {};
// 先遍历父属性进行和子属性合并
for (let k in parent) {
mergeFiled(k);
}
// 遍历子属性中父属性没有的属性进行合并
for (let k in child) {
if (!parent.hasOwnProperty(k)) {
mergeFiled(k);
}
}
//真正合并字段方法
function mergeFiled(k) {
//先判断是否是生命周期的属性
if (strats[k]) {
options[k] = strats[k](parent[k], child[k]);
} else {
// 非生命周期以外的合并
options[k] = child[k] ? child[k] : parent[k];
}
}
return options;
}
生命周期的调用
// src/lifecycle.js
export function callHook(vm, hook) {
// 依次执行生命周期对应的方法
const handlers = vm.$options[hook];
//遍历对应的生命周期
if (handlers) {
for (let i = 0; i < handlers.length; i++) {
handlers[i].call(vm); //生命周期里面的this指向当前实例
}
}
}
承接上文的this._init方法
export function initMixin (Vue: Class<Component>) {
Vue.prototype._init = function (options) {
const vm = this;
// 这里的this代表调用_init方法的对象(实例对象)
// this.$options就是用户new Vue的时候传入的属性和全局的Vue.options合并之后的结果
...
//vm.constructor=vm.prototype.constructor即指向Vue
//全局的Vue.options和new Vue的时候传入的属性合并之后的结果
vm.$options = mergeOptions(vm.constructor.options, options);
callHook(vm, "beforeCreate"); //初始化数据之前
// 初始化状态
initState(vm);
callHook(vm, "created"); //初始化数据之后
// 如果有el属性 进行模板渲染
if (vm.$options.el) {
vm.$mount(vm.$options.el);
}
};
}
挂载组件时的调用
// src/lifecycle.js
export function mountComponent(vm, el) {
vm.$el = el;
// 引入watcher的概念 这里注册一个渲染watcher 执行vm._update(vm._render())方法渲染视图
callHook(vm, "beforeMount"); //初始渲染之前
let updateComponent = () => {
vm._update(vm._render());
};
new Watcher(
vm,
updateComponent,
() => {
callHook(vm, "beforeUpdate"); //更新之前
},
true
);
callHook(vm, "mounted"); //渲染完成之后
}