Vue.js源碼分析(三)--render

render

在instance的render.js裏面可以找到renderMixin方法,裏面定義了_render方法:

    const { render, _parentVnode } = vm.$options

_parentVnode可以先暫時方瞎下,着重看render方法,其實就這一句:

      vnode = render.call(vm._renderProxy, vm.$createElement)

前者用來綁定this,生產環境就是vm,開發環境可能是個proxy對象,而後者則是在initRender函數中定義的,這就又回到了第一節的初始化中:

    initLifecycle(vm);
    initEvents(vm);
    initRender(vm);
    callHook(vm, "beforeCreate");
    initInjections(vm); // resolve injections before data/props
    initState(vm);
    initProvide(vm); // resolve provide after data/props
    callHook(vm, "created");

這幾個初始化我們之前看過了initState,除去inject和provide,其他應該都是很熟悉的東西,如生命週期,事件機制,再然後就是initRender了。

走到這個函數中,我們可以看到有兩個類似的方法調用:

  vm._c = (a, b, c, d) => createElement(vm, a, b, c, d, false)
  vm.$createElement = (a, b, c, d) => createElement(vm, a, b, c, d, true)

前者是編譯生成render函數創建VNode的方法,典型的有template編譯後的render;後者則是手寫render時執行的方法。

這裏可以稍微看一下createElement的函數簽名:

  context: Component,
  tag: any,
  data: any,
  children: any,
  normalizationType: any,
  alwaysNormalize: boolean

接着如果是後者會走一步:

  if (isTrue(alwaysNormalize)) {
    normalizationType = ALWAYS_NORMALIZE
  }

然後繼續傳遞normalizationType的值, 這裏不再展開,後面遇到再講。

扯遠了,回到_renderProxy中。

同樣是在init時做了個判斷:

    if (process.env.NODE_ENV !== "production") {
      initProxy(vm);
    } else {
      vm._renderProxy = vm;
    }

如果是生產環境vm._renderProxy 就是 vm實例,開發環境的話我們會轉到proxy.js中。

在這裏面,如果瀏覽器支持proxy,那麼就是利用proxy做了個攔截(並不是大家理解的響應式),攔截的目的是做一些提醒,典型的就是我們因爲粗心大意把data中的鍵寫錯了:

      `Property or method "${key}" is not defined on the instance but ` +
      'referenced during render. Make sure that this property is reactive, ' +
      'either in the data option, or for class-based components, by ' +
      'initializing the property. ' +

這裏會報錯其實就是利用proxy,傳入了一個getHander的函數幫助我們完成的,當然如果沒有proxy特性那麼也沒法做這個優化,就和生產環境的效果是一樣的了。

最後我們再回到render.js中的renderMixin裏面,我們剛剛走完了try的部分,沒問題的話會走到最後的finally部分,其中又有一個我們常見的錯誤:

"Multiple root nodes returned from render function. Render function " +
"should return a single root node.",

這個報錯的原因就是vnode還是一個array,以爲着template內部節點不唯一。

接下來

下一節我們開始看VNode。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章