- 开始 mount 挂载
- 创建 vNode
- render 方法渲染 vNode
- 创建 instance 实例
- 开始 init 初始化
- 优先处理 setup 上下文
- 优先初始化 props 和 slots
- 然后检测是否有 render 方法,有则不需要 compile 否则需要 compile 获取 render 方法
- 然后再适配 vue2.0 语法初始化 props(前面已经初始化完毕),inject,methods, data,computed,watch
- init 初始化完毕
- 优先处理 setup 上下文
- 开始创建实例 update 方法
- update 的 effect 回调函数有两套逻辑 mountComponent 和 updateComponent
- 两者都先进行 render 然后再 patch
- mount 挂载完毕
响应式数据挂载后触发执行收集 update 回调函数依赖,当响应式数据有变动会触发执行依赖走 updateComponent 逻辑重新渲染
mount
mount:
mount(rootContainer: HostElement, isHydrate?: boolean): any {
if (!isMounted) {
const vnode = createVNode(/*...*/) // 首先创建 vnode
// ...
if (isHydrate && hydrate) {/*...*/} else {
render(vnode, rootContainer) // render 方法渲染 vNode 这里调用 patch 方法
}
// ...
render 方法渲染 vNode 调用 patch 方法
patch:
const patch: PatchFn = (/*...*/) => {
// ...
const { type, ref, shapeFlag } = n2 // type vNode 类型根据不同类型做相应处理
switch (type) {
// ...
default:
if (shapeFlag & ShapeFlags.ELEMENT) {
// ...
} else if (shapeFlag & ShapeFlags.COMPONENT) {
processComponent(/*...*/) // process 方法一般有两种处理方式 首次加载 和 更新
// ...
instance
processComponent 中如果是首次加载则执行 mountComponent,createComponentInstance 方法创建组件实例:
const mountComponent: MountComponentFn = (/*...*/) => {
// instance 通过 createComponentInstance 方法创建
const instance: ComponentInternalInstance = (initialVNode.component = createComponentInstance(/*...*/))
// ...
createComponentInstance 创建实例
export function createComponentInstance(/*...*/) {
// ...
const instance: ComponentInternalInstance = {
// 初始化实例 state emit lifecycle hooks 等数据
}
if (__DEV__) {
instance.ctx = createRenderContext(instance) // 创建并绑定上下文 ctx
} else {
instance.ctx = { _: instance }
}
// ...
return instance
}
init
回到 mountComponent 开始 init 初始化:
const mountComponent: MountComponentFn = (/*...*/) => {
// ...
if (__DEV__) {
startMeasure(instance, `mount`) // start mount
}
// ...
if (__DEV__) {
startMeasure(instance, `init`) // start init
}
setupComponent(instance) // 开始创建 setup 上下文
// ...
setupComponent 开始处理组件 setup 上下文,在开始之前先处理 props 的初始化:
export function setupComponent(/*...*/) {
// ...
initProps(instance, props, isStateful, isSSR) // 开始初始化 prop
// initProps 会执行校验、创建 shallowReactive
initSlots(instance, children) // 开始初始化 slot
// ...
setupStatefulComponent(instance, isSSR) // 这里开始处理 setup 实例方法
// ...
return setupResult
}
执行 setup 函数或触发 finishComponentSetup:
function setupStatefulComponent(/*...*/) {
// ...
const { setup } = Component
if (setup) {
// 这里有一堆处理 setup 上下文的方法
} else {
finishComponentSetup(instance, isSSR)
}
}
最后触发 finishComponentSetup 方法:
- 检测实例是否有 render 方法,没有则 compile 这里就是 runtime compile 运行时编译,如果有 render 方法则不需要运行时编译
- 适配 vue2.0 语法,初始化顺序是 props,inject,methods, data,computed,watch
function finishComponentSetup(/*...*/) {
// ...
if (__NODE_JS__ && isSSR) {
// ...
} else if (!instance.render) {
if (compile && Component.template && !Component.render) {
if (__DEV__) {
startMeasure(instance, `compile`) // 开始执行 compile
}
Component.render = compile(Component.template, {/*...*/})
if (__DEV__) {
endMeasure(instance, `compile`) // 结束执行 compile
}
}
// ...
// 这里适配 vue2.0 的旧语法 applyOptions 通过如下顺序初始化:
// - props (already done outside of this function)
// - inject
// - methods
// - data (deferred since it relies on `this` access)
// - computed
// - watch (deferred since it relies on `this` access)
if (__FEATURE_OPTIONS_API__) {
currentInstance = instance
applyOptions(instance, Component) // 适配 vue2.0
currentInstance = null
}
// ...
回到 mountComponent 方法中,init 初始化结束
renderEffect
renderEffect 创建实例 update 方法完毕后 mount 完成
setupRenderEffect(/*...*/)
if (__DEV__) {
endMeasure(instance, `mount`) // mount 结束
}
// ...
setupRenderEffect:
- update effect 内的回调函数会在 instance 绑定的响应式数据变化的时候触发
- update effect 内部判断是首次挂载 mountComponent 还是更新 updateComponent
- 首先会 render 然后再进行 patch 操作
const setupRenderEffect: SetupRenderEffectFn = (/*...*/) => {
instance.update = effect(function componentEffect() {
// mountComponent
if (!instance.isMounted) {
// 重新渲染 render
if (__DEV__) {
startMeasure(instance, `render`)
}
const subTree = (instance.subTree = renderComponentRoot(instance))
if (__DEV__) {
endMeasure(instance, `render`)
}
// 渲染完毕后开始 patch
if (el && hydrateNode) {/*...*/} else {
if (__DEV__) {
startMeasure(instance, `patch`)
}
patch(
null, // mountComponent时 为 null
subTree,
/*...*/
)
if (__DEV__) {
endMeasure(instance, `patch`)
}
// ...
}
// ...
} else {
// updateComponent
// ...
// 同样的需要先 render
if (__DEV__) {
startMeasure(instance, `render`)
}
const nextTree = renderComponentRoot(instance)
if (__DEV__) {
endMeasure(instance, `render`)
}
const prevTree = instance.subTree
// 开始 patch
if (__DEV__) {
startMeasure(instance, `patch`)
}
patch( // 开始 patch 对比两个节点树
prevTree,
nextTree,
/*...*/
)
if (__DEV__) {
endMeasure(instance, `patch`)
}
// ...
最后 mount 结束