VUE源码解析(2)

下面来梳理一下父子组件的解析过程

一个组件import之后 经过render解析 并且传进_createElement方法

 vnode = createComponent(tag, data, context, children);


这里的context是vm 紧接着又调用了createComponent方法
这里有两个特别重要的函数 就是 Ctor = baseCtor.extend(Ctor) 和installComponentHooks(data);
这里的baseCtor.extend 是让Ctor 继承Vue 并且返回构造器
installComponentHooks 初始化data 给data安装钩子函数 在 componentVNodeHooks 中

function createComponent (
  Ctor,
  data,
  context,
  children,
  tag
) {
  if (isUndef(Ctor)) {
    return
  }

  var baseCtor = context.$options._base; //实际上就是Vue

  // plain options object: turn it into a constructor
  if (isObject(Ctor)) { //每个组件都有一个独立的构造器
    Ctor = baseCtor.extend(Ctor);//Vue扩展Ctor 创建Sub 继承Vue 参数放进sub.options 返回Sub 构造函数
  }

  // if at this stage it's not a constructor or an async component factory,
  // reject.
  if (typeof Ctor !== 'function') {
    if (process.env.NODE_ENV !== 'production') {
      warn(("Invalid Component definition: " + (String(Ctor))), context);
    }
    return
  }

  // async component
  var asyncFactory;
  if (isUndef(Ctor.cid)) {
    asyncFactory = Ctor;
    Ctor = resolveAsyncComponent(asyncFactory, baseCtor);
    if (Ctor === undefined) {
      // return a placeholder node for async component, which is rendered
      // as a comment node but preserves all the raw information for the node.
      // the information will be used for async server-rendering and hydration.
      return createAsyncPlaceholder(
        asyncFactory,
        data,
        context,
        children,
        tag
      )
    }
  }

  data = data || {};

  // resolve constructor options in case global mixins are applied after
  // component constructor creation
  resolveConstructorOptions(Ctor);//检查options和全局的是否冲突

  // transform component v-model data into props & events
  if (isDef(data.model)) {
    transformModel(Ctor.options, data);
  }

  // extract props
  var propsData = extractPropsFromVNodeData(data, Ctor, tag);

  // functional component
  if (isTrue(Ctor.options.functional)) {
    return createFunctionalComponent(Ctor, propsData, data, context, children)
  }

  // extract listeners, since these needs to be treated as
  // child component listeners instead of DOM listeners
  var listeners = data.on;
  // replace with listeners with .native modifier
  // so it gets processed during parent component patch.
  data.on = data.nativeOn;

  if (isTrue(Ctor.options.abstract)) {
    // abstract components do not keep anything
    // other than props & listeners & slot

    // work around flow
    var slot = data.slot;
    data = {};
    if (slot) {
      data.slot = slot;
    }
  }

  // install component management hooks onto the placeholder node

  installComponentHooks(data); //安装一些组件的钩子

  // return a placeholder vnode //生成一个vnode 这和之前的vnode不一样 是一个组件vnode
  var name = Ctor.options.name || tag;
  var vnode = new VNode(
    ("vue-component-" + (Ctor.cid) + (name ? ("-" + name) : '')),
    data, undefined, undefined, undefined, context,
    { Ctor: Ctor, propsData: propsData, listeners: listeners, tag: tag, children: children },
    asyncFactory
  );
  //这时候的Ctor已经不是原来的tag 而是extend返回的sub构造器
  return vnode
}

componentVNodeHooks代码如下

var componentVNodeHooks = {
  init: function init (vnode, hydrating) {
    if (
      vnode.componentInstance &&
      !vnode.componentInstance._isDestroyed &&
      vnode.data.keepAlive
    ) {
      // kept-alive components, treat as a patch
      var mountedNode = vnode; // work around flow
      componentVNodeHooks.prepatch(mountedNode, mountedNode);
    } else {
      var child = vnode.componentInstance = createComponentInstanceForVnode( //返回子组件vm实例
        vnode,  //第一次是占位vnode
        activeInstance  //返回的 new Vue实例
      );
      child.$mount(hydrating ? vnode.elm : undefined, hydrating);
    }
  },

这里的createComponentInstanceForVnode 把createComponent返回的vnode 和activeInstance 传入
并且返回vm实例

function createComponentInstanceForVnode (
  // we know it's MountedComponentVNode but flow doesn't
  vnode,
  // activeInstance in lifecycle state
  parent //这里的parent实际上是一个vm的实例
) {
  console.log(vnode)

  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;
  }//componentOptions是VNode 构造函数的第七个参数  在createComponent里返回的vnode
  return new vnode.componentOptions.Ctor(options) //这个ctor其实就是一个组件的构造器Sub
  //这里因为是实例化 就会执行构造器sub的 构造函数中的init init是继承自Vue
}

注意这个new vnode.componentOptions.Ctor 就会激活构造器sub的 init方法 由于init方法继承自Vue 所以就会 执行 Vue.prototype._init 里的initInternalComponent 设置父子组件关系
然后再componentVNodeHooks 中的init方法中手动调用$mount 实现update 并且在update中的createElm函数只要一遇到组件 就会调用createComponent 实现深度遍历 最后把最里面的子组件渲染完成 依次向上插入父组件的 最后在insert在最外面

你可能感兴趣的:(VUE源码解析(2))