Appearance
五、生命周期的合并
0、生命周期方法的使用
js
// 1、全局mixin混入使用
Vue.mixin({
created: function a() {
console.log('created 1');
}
})
// 2、在options中以属性方式使用
let vm = new Vue({
el: '#app',
created() {
// 生命周期就是回调函数,先订阅号,后续触发
console.log('created 3');
}
})1、Mixin原理
js
// src\global-api\index.js
import { mergeOptions } from "../../util";
// 定义全局API
export function initGlobalApi(Vue) {
Vue.options = {};
// 定义混入的静态方法
Vue.mixin = function(mixin) {
// 合并对象-生命周期
this.options = mergeOptions(this.options, mixin);
}
}2、合并生命周期
js
// 01vue\util.js
// 定义完整的生命周期数组
export const LIFECYCLE_HOOKS = [
'beforeCreate',
'created',
'beforeMount',
'mounted',
'beforeUpdate',
'updated',
'beforeDestroy',
'destroyed'
];
// 使用策略模式进行不同方法的调用
const strats = {};
strats.data = function(parentVal, childVal) {
return childVal;
}
strats.computed = function() {}
strats.watch = function() {}
// 生命周期的合并
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;
})
// 对象合并方法
export function mergeOptions(parent, child) {
const options = {};
// 1、处理父亲有,儿子有或没有的情况
for (let key in parent) {
mergeField(key);
}
// 2、处理儿子有,父亲没有:把儿子多余的属性赋予到父亲上
for (let key in child) {
if (!parent.hasOwnProperty(key)) {
mergeField(key);
}
}
function mergeField(key) {
// 根据key,采取不同的策略合并
if (strats[key]) {
options[key] = strats[key](parent[key], child[key]);
} else {
// todo 默认合并
options[key] = child[key];
}
}
return options;
}3、定义生命周期的调用函数
js
// 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
}
}
}4、在各个节点调用生命周期
js
// 调用beforeCreate和created
Vue.prototype._init = function(options) {
// 拿到当前实例
const vm = this
// 需要将用户自定义的options和全局的options做合并
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)
}
}
// 调用beforeMount和mounted
export function mountComponent(vm, el) {
vm.$el = el;
callHook(vm, 'beforeMount');
// 先调用render方法创建虚拟节点,再将虚拟节点渲染到页面上
vm._update(vm._render());
callHook(vm, 'mounted');
}