在 new Vue() 时, 外部会执行一个_init() 办法, 这个办法是在 initMixin(Vue) 中定义的
export function initMixin(Vue){Vue.prototupe_init = function (options){...}
}
当 new Vue() 执行完之后. 一系列的初始化都在_init 中启动
Vue.prototupe_init = function (options){
const vm = this;
vm._uid = uid++;
// 合并选项
vm.$options = mergeOptions(resolveConstructorOptions(vm.constructor),
options || {},
vm
)
// 开始一系列的初始化
vm._self = vm
initLifecycle(vm)
initEvents(vm)
initRender(vm)
callHook(vm, 'beforeCreate')
initInjections(vm)
initState(vm)
initProvide(vm)
callHook(vm, 'created')
}
合并 options 配置
合并选项有两种状况
- 初始化 new Vue
在执行 new Vue() 构造函数时, 参数是一个对象, 也就是用户自定义的配置, 会将它和 vue 之前定义的原型办法, 全局 API 合并成为一个新的 options 参数, 而后赋值给一个新的属性 $options
- 子组件初始化
如果是子组件初始化, 除了合并以上那些, 还会将父组件的参数进行合并, 比方 event props 等
执行一系列初始化办法
1. initLifecyle(vm)
次要作用是确认组件的父子关系, 初始化某些实例属性
export function initLifecycle (vm: Component) {
const options = vm.$options // 合并之后的 options
let parent = options.parent
// 找到第一个非形象父组件
if (parent && !options.abstract) {while (parent.$options.abstract && parent.$parent) {parent = parent.$parent}
parent.$children.push(vm)
}
// 找到后赋值
vm.$parent = parent
vm.$root = parent ? parent.$root : vm
vm.$children = []
vm.$refs = {}
vm._watcher = null
vm._inactive = null
vm._directInactive = false
vm._isMounted = false
vm._isDestroyed = false
vm._isBeingDestroyed = false
}
vue 是组件式开发的, 所以以后实例可能会是其余组件的子组件同时也是其余组件的父组件
initEvents(vm)
次要作用是将父组件在应用 v -on 或者 @注册的自定义事件增加到子组件的事件核心
export function initEvents (vm: Component) {
// 事件核心
vm._events = Object.create(null)
vm._hasHookEvent = false
// init parent attached events
// 通过合并 options 失去的事件
const listeners = vm.$options._parentListeners
if (listeners) {updateComponentListeners(vm, listeners)
}
}
通过合并后, 子组件就能够从 vm.$options.__parentListeners 读取到父组件传过来的自定义事件
initRender(vm)
次要作用是挂载能够将 render 函数转为 vnode 的办法
export function initRender(Vue) {
const options = vm.$options;
...
vm._c = (a, b, c, d) => createElement(vm, a, b, c, d, false) // 转化编译器的
vm.$createElement = (a, b, c, d) => createElement(vm, a, b, c, d, true) // 转化手写的
}
次要是挂载_c 和 $createElement 两个办法, 它们只是最初一个参数不同. 这两个参数都能够将 render 函数转化为 vnode, vm._c 转化的是通过编译器将 template 转换而来的 render. 而 $createElement 转换的是用户自定义的 render
callHook(vm, ‘beforeCreate’)
第一个生命周期 beforeCreate
- initLifecycle(vm) 确认组件的父子关系
- initEvents(vm) 将父组件的自定义事件传给子组件
- initRender(vm) 提供将 render 函数转换为 vnode 的办法
- beforeCreate 执行组件的 beforeCreate 办法
面试题:
请问能够在 beforeCreate 钩子内通过 this 拜访到 data 中定义的变量. 为什么以及请问这个钩子能够做什么
不能够拜访. 因为在 vue 初始化阶段, 这个时候 data 中的变量还没有被挂载到 this 上. 这个时候拜访会是 undefined. beforeCreate 在平时开发中用的比拟少, 而像插件外部的 install 办法通过 Vue.use 办法装置时个别会抉择 beforeCreate 这个钩子执行. 比方 vuex 和 vue-router