用vue也有一两年了,始终对vue一知半解,不怎么了解内部的执行过程,最近在看vue源码,还是不少收获的,其中不乏浏览器事件轮询机制、闭包、设计模式等,还是非常值得一读。本篇简要记录下vue的初始化过程,具体初始化过程及内容的时序如下图所示:
初始化主要执行了vue-dev\src\core\index.js和vue-dev\src\core\instance\index.js两个文件,具体执行代码如下:
vue-dev\src\core\instance\index.js
function Vue (options) { if (process.env.NODE_ENV !== 'production' && !(this instanceof Vue) ) { warn('Vue is a constructor and should be called with the `new` keyword') } this._init(options) } // 初始化vue _init方法 initMixin(Vue) // 初始化data, prop watch等 stateMixin(Vue) // 初始化发布-订阅事件模型 eventsMixin(Vue) // 初始化组件生命周期钩子 lifecycleMixin(Vue) // 初始化nextTick, render renderMixin(Vue)
vue-dev\src\core\index.js
initGlobalAPI(Vue) Object.defineProperty(Vue.prototype, '$isServer', { get: isServerRendering }) Object.defineProperty(Vue.prototype, '$ssrContext', { get () { /* istanbul ignore next */ return this.$vnode && this.$vnode.ssrContext } }) // expose FunctionalRenderContext for ssr runtime helper installation Object.defineProperty(Vue, 'FunctionalRenderContext', { value: FunctionalRenderContext }) Vue.version = '__VERSION__'
在方法initGlobalAPI中,会初始化一切Vue全局的工具方法,像我们常用的全局注册组件Vue.components,全局注册指令Vue.directives,set/delete等,具体代码如下所示:
export function initGlobalAPI (Vue: GlobalAPI) { // config const configDef = {} configDef.get = () => config if (process.env.NODE_ENV !== 'production') { configDef.set = () => { warn( 'Do not replace the Vue.config object, set individual fields instead.' ) } } Object.defineProperty(Vue, 'config', configDef) // exposed util methods. // NOTE: these are not considered part of the public API - avoid relying on // them unless you are aware of the risk. Vue.util = { warn, extend, mergeOptions, defineReactive } Vue.set = set Vue.delete = del Vue.nextTick = nextTick // 2.6 explicit observable API Vue.observable = <T>(obj: T): T => { observe(obj) return obj } // 初始化Vue构造函数的options,初始属性为components,directives,filters Vue.options = Object.create(null) ASSET_TYPES.forEach(type => { Vue.options[type + 's'] = Object.create(null) }) // this is used to identify the "base" constructor to extend all plain-object // components with in Weex's multi-instance scenarios. // _base属性 Vue.options._base = Vue extend(Vue.options.components, builtInComponents) // 初始化vue.use api initUse(Vue) // 初始化mixins api initMixin(Vue) // 初始化extend api initExtend(Vue) // 初始化component,directive,filter initAssetRegisters(Vue) }
在首次项目初始化的过程中,会初始化几个Vue的私有方法,后面在实例化Vue的时候,会经常用到,比如Vue实例上会挂载_init方法,在我们实例化Vue的过程中,实际上调用的是this._init方法,接收的参数options就是我们初始化时的配置项。_render方法是在我们挂载DOM时会被调用,之后会调用_update方法,每次DOM的初始化、更新,都会执行_update方法。