Open chenfaxiang opened 6 years ago
// install component management hooks onto the placeholder node installComponentHooks(data)
Vue.js 利用 VNode 在 patch 的流程中对外暴露了不同时机的钩子函数,方便使用者利用钩子函数做不同的事情;installComponentHooks() 方法的定义如下:
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 函数,如下:
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 部分,如下:
installComponentHooks
// 实例化 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 并返回;
new VNode
vnode
综上,在 createComponent 的过程中,有三个比较重要的步骤就是构造子类构造函数、安装组件钩子函数、实例化 vnode,而最终返回了 vnode。
createComponent
安装组件钩子函数
Vue.js 利用 VNode 在 patch 的流程中对外暴露了不同时机的钩子函数,方便使用者利用钩子函数做不同的事情;
installComponentHooks()
方法的定义如下:在初始化一个
Component
类型的VNode
的过程中出现了componentVNodeHooks
和mergeHook
函数,如下:在前面的
installComponentHooks
执行完之后,就到了实例化 VNode 部分,如下:通过
new VNode
实例化一个vnode
并返回;综上,在
createComponent
的过程中,有三个比较重要的步骤就是构造子类构造函数、安装组件钩子函数、实例化vnode
,而最终返回了vnode
。