VUE源碼解析(2)

下面來(lái)梳理一下父子組件的解析過(guò)程

一個(gè)組件import之后 經(jīng)過(guò)render解析 并且傳進(jìn)_createElement方法

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


這里的context是vm 緊接著又調(diào)用了createComponent方法
這里有兩個(gè)特別重要的函數(shù) 就是 Ctor = baseCtor.extend(Ctor) 和installComponentHooks(data);
這里的baseCtor.extend 是讓Ctor 繼承Vue 并且返回構(gòu)造器
installComponentHooks 初始化data 給data安裝鉤子函數(shù) 在 componentVNodeHooks 中

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

  var baseCtor = context.$options._base; //實(shí)際上就是Vue

  // plain options object: turn it into a constructor
  if (isObject(Ctor)) { //每個(gè)組件都有一個(gè)獨(dú)立的構(gòu)造器
    Ctor = baseCtor.extend(Ctor);//Vue擴(kuò)展Ctor 創(chuàng)建Sub 繼承Vue 參數(shù)放進(jìn)sub.options 返回Sub 構(gòu)造函數(shù)
  }

  // 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 //生成一個(gè)vnode 這和之前的vnode不一樣 是一個(gè)組件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
  );
  //這時(shí)候的Ctor已經(jīng)不是原來(lái)的tag 而是extend返回的sub構(gòu)造器
  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實(shí)例
        vnode,  //第一次是占位vnode
        activeInstance  //返回的 new Vue實(shí)例
      );
      child.$mount(hydrating ? vnode.elm : undefined, hydrating);
    }
  },

這里的createComponentInstanceForVnode 把createComponent返回的vnode 和activeInstance 傳入
并且返回vm實(shí)例

function createComponentInstanceForVnode (
  // we know it's MountedComponentVNode but flow doesn't
  vnode,
  // activeInstance in lifecycle state
  parent //這里的parent實(shí)際上是一個(gè)vm的實(shí)例
) {
  console.log(vnode)

  var options = {
    _isComponent: true,   //設(shè)置是不是組件
    _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 構(gòu)造函數(shù)的第七個(gè)參數(shù)  在createComponent里返回的vnode
  return new vnode.componentOptions.Ctor(options) //這個(gè)ctor其實(shí)就是一個(gè)組件的構(gòu)造器Sub
  //這里因?yàn)槭菍?shí)例化 就會(huì)執(zhí)行構(gòu)造器sub的 構(gòu)造函數(shù)中的init init是繼承自Vue
}

注意這個(gè)new vnode.componentOptions.Ctor 就會(huì)激活構(gòu)造器sub的 init方法 由于init方法繼承自Vue 所以就會(huì) 執(zhí)行 Vue.prototype._init 里的initInternalComponent 設(shè)置父子組件關(guān)系
然后再componentVNodeHooks 中的init方法中手動(dòng)調(diào)用$mount 實(shí)現(xiàn)update 并且在update中的createElm函數(shù)只要一遇到組件 就會(huì)調(diào)用createComponent 實(shí)現(xiàn)深度遍歷 最后把最里面的子組件渲染完成 依次向上插入父組件的 最后在insert在最外面

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容