前言
vue2 采用 monorepo 单体仓库管理模式管理项目代码;vue2 重点源码路径 vue/src/core/instance/index.ts
从 new Vue()实例化开始
Vue 初始化主要就干了几件事情,合并配置,初始化生命周期,初始化事件中心,初始化渲染,初始化 data、props、computed、watcher 等等。
function Vue(options) {
if (__DEV__ && !(this instanceof Vue)) {
warn('Vue is a constructor and should be called with the `new` keyword')
}
this._init(options)
}
# init方法 #
Vue.prototype._init = function (options?: Record<string, any>) {
const vm: Component = this
vm._uid = uid++
vm._isVue = true
// 实例响应不通知观察
vm.__v_skip = true
// effect scope
vm._scope = new EffectScope(true /* detached */)
vm._scope._vm = true
// merge options合并配置
if (options && options._isComponent) {
// 只是做了简单一层对象赋值,并不涉及到递归、合并策略等复杂逻辑。因此要比mergeOptions快
initInternalComponent(vm, options as any)
} else {
vm.$options = mergeOptions(
resolveConstructorOptions(vm.constructor as any),
options || {},
vm
)
}
/* 给实例添加代理监听;添加获取vm上面的属性、值 return target[key] */
if (__DEV__) { // process.env.NODE_ENV !== 'production'
initProxy(vm)
} else {
vm._renderProxy = vm
}
vm._self = vm
initLifecycle(vm)
initEvents(vm)
initRender(vm)
callHook(vm, 'beforeCreate', undefined, false)
initInjections(vm) // resolve injections before data/props
initState(vm)
initProvide(vm) // resolve provide after data/props
callHook(vm, 'created')
if (vm.$options.el) { // 挂载一个未挂载的实例到元素上
vm.$mount(vm.$options.el)
}
}
1.给实例 vm 添加一些基础属性配置、记录标识;合并 options 配置项:
(1).resolveConstructorOptions:简单返回
Vue.options = Object.create(null)
ASSET_TYPES.forEach(type => {
Vue.options[type + 's'] = Object.create(null)
})
Vue.options.components = {}
Vue.options.directives = {}
Vue.options.filters = {}
Vue.options._base = Vue
(2).根据不同的合并策略合并:props、inject、directives、(合并子选项是原始的对象时合并 extends、mixins)、合并其它属性
- 初始化生命周期:赋值root;给实例初始化一些属性(refs、_provided、_watcher、_inactive、_directInactive、_isMounted、_isDestroyed、_isBeingDestroyed )
- 初始化事件中心: vm._events = Object.create(null)
- 初始化渲染:创建scopedSlots;以及渲染函数_c、$createElement=>vnode(虚拟的 node 节点)
- beforeCreate
- v2 的 inject、Provide 非响应式;v3 的 inject、Provide 根据传入类型可响应,可非响应 *
- initInjections:初始化注入数据;toggleObserving 关闭响应,通过 defineReactive 代理到实例访问;toggleObserving 开启响应
- initState:初始化 props、methods、data、computed、watcher
- initProvide:初始化该组件的下级注入数据
- created
- $mount:执行_update=>patch 转成真正的 dom
渲染过程:
1. html字符串 → render函数 → vnode → 真实dom节点
2. render函数 → vnode → 真实dom节点
src/core/instance/lifecycle.js
export function mountComponent (
vm: Component,
el: ?Element,
hydrating?: boolean
): Component {
vm.$el = el
// ...
callHook(vm, 'beforeMount')
let updateComponent
/* istanbul ignore if */
if (process.env.NODE_ENV !== 'production' && config.performance && mark) {
updateComponent = () => {
const name = vm._name
const id = vm._uid
const startTag = `vue-perf-start:${id}`
const endTag = `vue-perf-end:${id}`
mark(startTag)
const vnode = vm._render()
mark(endTag)
measure(`vue ${name} render`, startTag, endTag)
mark(startTag)
vm._update(vnode, hydrating)
mark(endTag)
measure(`vue ${name} patch`, startTag, endTag)
}
} else {
updateComponent = () => {
vm._update(vm._render(), hydrating)
}
}
new Watcher(vm, updateComponent, noop, {
before () {
if (vm._isMounted) {
callHook(vm, 'beforeUpdate')
}
}
}, true /* isRenderWatcher */)
hydrating = false
if (vm.$vnode == null) {
vm._isMounted = true
callHook(vm, 'mounted')
}
return vm
}
- beforeMount:dom 挂载之前
- 执行渲染函数
- mounted:在 dom 渲染完成之后
- beforeUpdate:当数据更新之后才会执行【new Watcher()中】
- updated:【在发布消息时触发】
- beforeDestroy:在组件销毁之前,此时 data、methods 可以用,释放内存
- destroyed 以及 activated & deactivated