呜呼~ vue生命周期原理原来如此

1,081 阅读2分钟

前言

相信vue生命周期的几个钩子大家都很清楚,那它具体是怎么实现的呢?

在讲生命周期原理之前,我们还要先讲一下vue.mixin这个和生命周期有关的api。

mixin

简介

vue官方文档是这么介绍的

全局注册一个混入,影响注册之后所有创建的每个 Vue 实例。插件作者可以使用混入,向组件注入自定义的行为。不推荐在应用代码中使用

通俗点讲,就是对Vue构造函数做一些混入操作,影响每个vue实例。

原理

通过mergeOptions 将各个Vue.mixin的 options 合并到Vue.options

import {mergeOptions} from '../util/index.js'
export function initGlobalAPI(Vue){
    Vue.options = {};

    Vue.mixin = function (mixin) {
        this.options = mergeOptions(this.options,mixin);
        return this;
    }
}

采用策略模式,不同options(比如data、method、lifeCycleHooks)对应不同合并策略。

let lifeCycleHooks = [
    'beforeCreate',
    'created',
    'beforeMount',
    'mounted',
    'beforeUpdate',
    'updated',
    'beforeDestroy',
    'destroyed',
]
let strats = {}; // 存放各种策略
//   {}     {beforeCreate:Fn} => {beforeCreate:[fn]}
//   {beforeCreate:[fn]}    {beforeCreate:fn}   => {beforeCreate:[fn,fn]}

function mergeHook(parentVal, childVal) {
    if (childVal) {
        if (parentVal) {
            return parentVal.concat(childVal); // 后续
        } else {
            return [childVal]; // 第一次
        }
    } else {
        return parentVal
    }
}
lifeCycleHooks.forEach(hook => {
    strats[hook] = mergeHook
});
export function mergeOptions(parent, child) {
    const options = {}; // 合并后的结果
    for (let key in parent) {
        mergeField(key);
    }
    for (let key in child) {
        if (parent.hasOwnProperty(key)) {
            continue;
        }
        mergeField(key);
    }

    function mergeField(key) {
        let parentVal = parent[key];
        let childVal = child[key];
        // 策略模式
        if (strats[key]) { // 如果有对应的策略就调用对应的策略即可
            options[key] = strats[key](parentVal, childVal)
        } else {
            if (isObject(parentVal) && isObject(childVal)) {
                options[key] = { ...parentVal, ...childVal }
            } else {
                options[key] = child[key] || parent[key];
            }
        }
    }
    return options
}

生命周期原理

1.合并生命周期

合并vm.$options 上和Vue.options,也是通过上述mergeOptions方法

  Vue.prototype._init = function(options) {
//...
        vm.$options = mergeOptions(vm.constructor.options, options); 
    }

2.调用生命周期

通过callHook找到实例的钩子,让钩子数组里的方法依次执行。

export function callHook(vm,hook){
    let handlers = vm.$options[hook];
    if(handlers){
        for(let i =0; i < handlers.length;i++){
            handlers[i].call(vm)
        }
    }
}

3.初始化流程中调用生命周期

在初始化流程中的不同阶段调用callhook

Vue.prototype._init = function (options) {
    const vm = this;
    vm.$options = mergeOptions(vm.constructor.options,options);
    // 初始化状态
    callHook(vm,'beforeCreate');
    initState(vm);
    callHook(vm,'created');
    if (vm.$options.el) {
    	vm.$mount(vm.$options.el);
    }
}

上面是手写的简易版实现原理

我们再来看看源码😊

没错吧,源码就是通过callHook来实现vue的生命周期原理。

小结

vue的生命周期原理,就是将各个生命周期里的方法合并,存到数组里。在通过callhook,来调用各个生命周期里对应的方法。最后在初始化流程中的不同阶段调用对应的callhook