在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