context就是vue对象:

那么这个components 是什么时候加进去的,他在组件变成vnode的时候,有了初始化的信息来源.

image.png

$options信息如下:

image.png

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:

image.png

_render所依赖的 render函数如下

image.png

_App_vue__WEBPACK_IMPORTED_MODULE_2__["default"]

是什么呢?
image.png

可以看出,这个就是 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

image.png

但是这个时候 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 hydrate 就出来了


webpack_devsave
16 声望0 粉丝

a