共计 3106 个字符,预计需要花费 8 分钟才能阅读完成。
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 就进去了