1 componentVNodeHooks
组件生命周期钩子包含四个关键钩子函数:
ts
const componentVNodeHooks = {
init(vnode, hydrating) {
// 处理组件初始化
// 1. 处理 keep-alive 组件
// 2. 创建组件实例并挂载
},
prepatch(oldVnode, vnode) {
// 组件更新
},
insert(vnode) {
// 组件插入
},
destroy(vnode) {
// 组件销毁
}
}
2. createComponent
创建组件的核心方法。将组件元素转换为组件 VNode
。
譬如:
vue
<my-component />
转换为组件 VNode
后,VNode
的 componentOptions
属性中包含组件的构造函数 Ctor
。
ts
export function createComponent(Ctor, data, context, children, tag) {
// 1. 组件构造函数检查和处理
if (isObject(Ctor)) {
Ctor = baseCtor.extend(Ctor) // 将组件配置对象转为构造函数
}
// 2. 异步组件处理
if (isUndef(Ctor.cid)) {
asyncFactory = Ctor
Ctor = resolveAsyncComponent(asyncFactory, baseCtor)
// 返回注释节点占位符
}
// 3. 处理组件数据
// 处理 v-model
if (isDef(data.model)) {
transformModel(Ctor.options, data)
}
// 4. 提取 props
const propsData = extractPropsFromVNodeData(data, Ctor, tag)
// 5. 处理函数式组件
if (isTrue(Ctor.options.functional)) {
return createFunctionalComponent(...)
}
// 6. 处理事件监听器
const listeners = data.on
data.on = data.nativeOn
// 7. 安装组件钩子函数
installComponentHooks(data)
// 8. 创建并返回组件 VNode
const vnode = new VNode(...)
return vnode
}
核心功能:
- 将组件配置转换为构造函数
- 处理异步组件
- 处理组件数据(
props
、events
、slots
等) - 安装组件钩子函数
- 创建组件
VNode
3. createComponentInstanceForVnode
根据组件 VNode
创建组件实例,也就是转化为 Vue
实例:
ts
function createComponentInstanceForVnode(
vnode,
// activeInstance in lifecycle state
parent
) {
const options = {
_isComponent: true,
_parentVnode: vnode,
parent
}
// check inline-template render functions
const inlineTemplate = vnode.data.inlineTemplate
if (isDef(inlineTemplate)) {
options.render = inlineTemplate.render
options.staticRenderFns = inlineTemplate.staticRenderFns
}
return new vnode.componentOptions.Ctor(options)
}
4. installComponentHooks
安装组件钩子函数:
- 将组件的生命周期钩子(
init
、prepatch
、insert
、destroy
)安装到 VNode 的data.hook
中 - 处理钩子函数的合并
ts
function installComponentHooks(data) {
const hooks = data.hook || (data.hook = {})
for (let i = 0; i < hooksToMerge.length; i++) {
const key = hooksToMerge[i]
const existing = hooks[key]
const toMerge = componentVNodeHooks[key]
if (existing !== toMerge && !(existing && existing._merged)) {
hooks[key] = existing ? mergeHook(toMerge, existing) : toMerge
}
}
}