context就是vue对象:
那么这个components 是什么时候加进去的,他在组件变成vnode的时候,有了初始化的信息起源.
$options信息如下:
if ((!data || !data.pre) && isDef(Ctor = resolveAsset(context.$options, 'components', tag))) { // component vnode = createComponent(Ctor, data, context, children, tag);}
在 entry-client文件里
$mount引发的 update逻辑呈现了这个
vm._update(vm._render(), hydrating);
初始化的vue的 _uid为 2:
_render所依赖的 render函数如下
_App_vue__WEBPACK_IMPORTED_MODULE_2__["default"]
是什么呢?
能够看出,这个就是 vue-loader 解析后造成的选项参数。
所以在_render生成节点时,就用上了这个
vnode = render.call(vm._renderProxy, vm.$createElement);
最终会走到这个函数里来,带上的context就是 _uid为2的vue对象
function _createElement ( context, tag, data, children, normalizationType) {
生成组件vnode是通过这个分支进去的
} else { // direct component options / constructor vnode = createComponent(tag, data, context, children); }
最初生成了一个vnode,带有一个 componentOptions 属性:
{ Ctor: Ctor, propsData: propsData, listeners: listeners, tag: tag, children: children }
然而此时 没有呈现文中结尾所说的 _uid为3的vue?
咱们接下来看 刚刚提到的
vm._update(vnode, hydrating);
这个会进入一个 patch过程
vm.$el = vm.__patch__(vm.$el, vnode, hydrating, false /* removeOnly */);
属于 元素和 组件vnode进行patch的过程
首先是注水操作
hydrate(oldVnode, vnode, insertedVnodeQueue)
注水时 会碰到这一步,因为这是一个有hook.init的组件
if (isDef(data)) { if (isDef(i = data.hook) && isDef(i = i.init)) { i(vnode, true /* hydrating */); } if (isDef(i = vnode.componentInstance)) { // child component. it should have hydrated its own tree. initComponent(vnode, insertedVnodeQueue); return true } }
这外面就会生成一个新的vue:
function createComponentInstanceForVnode ( vnode, // we know it's MountedComponentVNode but flow doesn't parent // activeInstance in lifecycle state) { var options = { _isComponent: true, _parentVnode: vnode, parent: parent }; // check inline-template render functions var inlineTemplate = vnode.data.inlineTemplate; if (isDef(inlineTemplate)) { options.render = inlineTemplate.render; options.staticRenderFns = inlineTemplate.staticRenderFns; } return new vnode.componentOptions.Ctor(options)}
并且赋值给 VNODE对象
var child = vnode.componentInstance = createComponentInstanceForVnode( vnode, activeInstance );
最初还来了一个$mount
child.$mount(hydrating ? vnode.elm : undefined, hydrating);
原来这个是来源于这里的 child就是 _uid:3
然而这个时候 options里还没有 components
错了,在
new vnode.componentOptions.Ctor(options)
的时候就曾经有了
其实是来源于
function createComponent ( Ctor, data, context, children, tag) { if (isUndef(Ctor)) { return } var baseCtor = context.$options._base; // plain options object: turn it into a constructor if (isObject(Ctor)) { debugger Ctor = baseCtor.extend(Ctor); }
Ctor = baseCtor.extend(Ctor); 这里会把 options进行合并
Sub.options = mergeOptions( Super.options, extendOptions );
到此,起源终于进去了:
function initInternalComponent (vm, options) { var opts = vm.$options = Object.create(vm.constructor.options); // doing this because it's faster than dynamic enumeration. var parentVnode = options._parentVnode; opts.parent = options.parent; opts._parentVnode = parentVnode; var vnodeComponentOptions = parentVnode.componentOptions; opts.propsData = vnodeComponentOptions.propsData; opts._parentListeners = vnodeComponentOptions.listeners; opts._renderChildren = vnodeComponentOptions.children; opts._componentTag = vnodeComponentOptions.tag; if (options.render) { opts.render = options.render; opts.staticRenderFns = options.staticRenderFns; }}
vm.$options = Object.create(vm.constructor.options);
看见没,这里就会产生 一个_proto,找不到的属性会去Object.create的参数里找。
总结一遍,就是在 vue-loader里生成好的,而后再 mount的时候 进行 hydrate,再生成一个组件式VNODE,这个再进行render dydrate 就进去了