-
Notifications
You must be signed in to change notification settings - Fork 1
Open
Description
安装组件钩子函数
// install component management hooks onto the placeholder node
installComponentHooks(data)Vue.js 利用 VNode 在 patch 的流程中对外暴露了不同时机的钩子函数,方便使用者利用钩子函数做不同的事情;installComponentHooks() 方法的定义如下:
function installComponentHooks (data: VNodeData) {
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
}
}
}在初始化一个 Component 类型的 VNode 的过程中出现了 componentVNodeHooks 和 mergeHook 函数,如下:
// inline hooks to be invoked on component VNodes during patch
const componentVNodeHooks = {
init (vnode: VNodeWithData, hydrating: boolean): ?boolean {
if (
vnode.componentInstance &&
!vnode.componentInstance._isDestroyed &&
vnode.data.keepAlive
) {
// kept-alive components, treat as a patch
const mountedNode: any = vnode // work around flow
componentVNodeHooks.prepatch(mountedNode, mountedNode)
} else {
const child = vnode.componentInstance = createComponentInstanceForVnode(
vnode,
activeInstance
)
child.$mount(hydrating ? vnode.elm : undefined, hydrating)
}
},
prepatch (oldVnode: MountedComponentVNode, vnode: MountedComponentVNode) {
const options = vnode.componentOptions
const child = vnode.componentInstance = oldVnode.componentInstance
updateChildComponent(
child,
options.propsData, // updated props
options.listeners, // updated listeners
vnode, // new parent vnode
options.children // new children
)
},
insert (vnode: MountedComponentVNode) {
const { context, componentInstance } = vnode
if (!componentInstance._isMounted) {
componentInstance._isMounted = true
callHook(componentInstance, 'mounted')
}
if (vnode.data.keepAlive) {
if (context._isMounted) {
// vue-router#1212
// During updates, a kept-alive component's child components may
// change, so directly walking the tree here may call activated hooks
// on incorrect children. Instead we push them into a queue which will
// be processed after the whole patch process ended.
queueActivatedComponent(componentInstance)
} else {
activateChildComponent(componentInstance, true /* direct */)
}
}
},
destroy (vnode: MountedComponentVNode) {
const { componentInstance } = vnode
if (!componentInstance._isDestroyed) {
if (!vnode.data.keepAlive) {
componentInstance.$destroy()
} else {
deactivateChildComponent(componentInstance, true /* direct */)
}
}
}
}
const hooksToMerge = Object.keys(componentVNodeHooks)
// 合并钩子函数的操作
function mergeHook (f1: any, f2: any): Function {
const merged = (a, b) => {
// flow complains about extra args which is why we use any
f1(a, b)
f2(a, b)
}
merged._merged = true
return merged
}在前面的 installComponentHooks 执行完之后,就到了实例化 VNode 部分,如下:
// 实例化 VNode
const vnode = new VNode(
`vue-component-${Ctor.cid}${name ? `-${name}` : ''}`,
data, undefined, undefined, undefined, context,
{ Ctor, propsData, listeners, tag, children },
asyncFactory
)
return vnode通过 new VNode 实例化一个 vnode 并返回;
综上,在 createComponent 的过程中,有三个比较重要的步骤就是构造子类构造函数、安装组件钩子函数、实例化 vnode,而最终返回了 vnode。
Metadata
Metadata
Assignees
Labels
No labels