_init方法的定义
_init方法的内部原理
callHook函数的内部于原理
new vue()被调用时,会首先进行一些初始化操作,然后进入模版编译阶段,然后进入挂载阶段。
import { initMixin } from './init'
import { stateMixin } from './state'
import { renderMixin } from './render'
import { eventsMixin } from './events'
import { lifecycleMixin } from './lifecycle'
import { warn } from '../util/index'
/*Github:https://github.com/answershuto*/
function Vue (options) { //vue 函数
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) //调用了这个函数 这个函数是定在原型上的
}
initMixin(Vue)
stateMixin(Vue)
eventsMixin(Vue)
lifecycleMixin(Vue)
renderMixin(Vue)
export default Vue
首先进行安全检查,在非生产环境下,如果没有用new来调用vue,则会在控制台报出警告。
调用this._init(options) 来执行初始化流程,
1、_Init方法的定义
通过initMixin方法将_init挂载到Vue构造函数的原型上,import { initMixin } from ‘./init’ (代码如上)
export function initMixin (Vue: Class<Component>) {
Vue.prototype._init = function (options) {
vm.$options = mergeOptions(
resolveConstructorOptions(vm.constructor),
options || {},
vm
)
initLifecycle(vm)
initEvents(vm)
initRender(vm)
callHook(vm, 'beforeCreate')
initInjections(vm) // resolve injections before data/props
initState(vm)
initProvide(vm) // resolve provide after data/props
callHook(vm, 'created')
// 如果用户在实例化时传递了el,则自动开启模版编译阶段和挂载阶段
// 如果没有el,则不进入下一个生命周期流程
// 用户需要执行$mount方法,手动开启模版编译与挂载阶段
if (vm.$options.el) {
vm.$mount(vm.$options.el)
}
}
}
vuejs会在初始化流程的不同时期通过callhook函数触发生命周期钩子。
resolveConstructorOptions 函数的作用:获取当前实例中构造函数的options选项及其所有父级的构造函数的options。
3、callHook函数的内部于原理
作用:触发用户设置的生命周期钩子。
beforeCreate
created
beforeMount
mounted
beforeUpdate
updated
beforeDestroy
destroyed
activated
deactivated
errorCaptured
值得注意的是:vuejs在合并options的过程中会找出options中所有key是钩子函数的名字,并将它转换成数组.
Q:为什么要转换成数组?
A:vue.minixin方法会将选项写入vue.options中,因此护i影响之后创建的所有vuejs实例,会发生一个现象:vue.mixin和用户在实例化vuejs时,如果设置了同一个生命周期钩子,在触发生命周期时,要同时触发这两个函数。转换成数组后,可以在同一个生命周期钩子列表中保存多个声明周期钩子。
实现:只需要从vm.$options中获取生命周期钩子列表,遍历列表,执行每一个生命周期钩子,触发。
function callHook (vm, hook) { // vuejs实例的this, 声明周期钩子的名称
var handlers = vm.$options[hook];
if (handlers) {
for (var i = 0, j = handlers.length; i < j; i++) {
try {
handlers[i].call(vm);
} catch (e) {
handleError(e, vm, (hook + " hook"));
}
}
}
}
使用try…catch 捕获钩子函数内发生的错误,并使用handleError处理错误,handleError会依次执行父组件的errorCaptured钩子函数与全局的config.errorHandler,这也是为什么生命周期钩子errorCaptured可以捕获子孙组件的错误。