vue.js 開發(fā)系列(二)Render 函數(shù)

上一篇說了項目搭建和結構,這篇說說vue 的render 函數(shù),比較核心的概念。去年寫過一點react,所以知道render 函數(shù)是用來創(chuàng)建虛擬dom 的,那個時候寫 jsx 還是不亦樂乎的。列出幾個問題作為這篇的結構:

  • render 函數(shù)的作用?
  • 組件中的render 函數(shù)什么時候執(zhí)行?
  • 什么時候需要在組件中寫 jsx ?

常遇到這個問題:

[Vue warn]: Failed to mount component: template or render function not defined

這個問題是由于當前寫的組件沒注冊為vue 組件,或者組件定義中沒有template/render,所以組件沒法和具體的element 掛載到一起,無法完成渲染。

render 的作用

render 函數(shù)實際上是template 的底層方法,通過調用createElement(h)來創(chuàng)建dom節(jié)點,實際上作用就是負責組件視圖渲染的!createElement是render的核心方法。Vue編譯的時候會把template 編譯為對應的render 方法,所以有了render方法就可以不寫template 了!

看實例:

<template>
  <div class="right-panel">
     <div class="right-panel-header">{title}</div>
     <div class="right-panel-content">
        {content}
     </div>
  </div>
</template>

如果不寫template,對應的render 則是

render(h) {
  return (
      <div class="right-panel">
        <div class="right-panel-header">{this.title}</div>
        <div class="right-panel-content">
          {this.content}
        </div>
      </div>
    );
}

從生命周期出發(fā),render執(zhí)行時機

與render 相關的生命周期

還是得把組件的生命周期搬出來,created 鉤子函數(shù)是組件injection和reactivity 屬性初始化后,比如props、data 初始化,后面關鍵的:如果有template,則把視圖編譯為render function,如果沒有則直接調用被override 的render 方法創(chuàng)建虛擬dom節(jié)點,并且把組件對應的 htmlElement 替換為 組件的dom 結構和數(shù)據(jù),最后觸發(fā)mounted 鉤子。

所以執(zhí)行順序是 beforeMount -- render(h, data) -- mounted .

什么時候需要定義render

上面那個實例,panel content 內容可以是外部傳入的一段內容(this.$props.content),假如內容很復雜呢,假如這個panel 組件需要接受用戶自定義的復雜content 呢? 這時候就需要接受外部傳入的函數(shù)來渲染一段dom。 這樣panel 只是個容器,把內容渲染交給外部模塊,實際上是組件拆分和模塊化的思想,使得panel 組件可以更好的復用。

我們把panel 的render 函數(shù)改為可以接受外部函數(shù):

render(h) {
    let contentNode = (<div>default content</div>);
    if (this.contentRender && this.contentRender instanceof Function) {
      contentNode = this.contentRender(h, this.data); 
// 把數(shù)據(jù)用外部函數(shù)來渲染成用戶想要的結構
    }
    console.warn(`rendering...`);
    return (
      <div class="right-panel">
        <div class="right-panel-header">Panel Header</div>
        <div class="right-panel-content">
          {contentNode}
// 插入dom 結構
        </div>
      </div>
    );
  }

contenRender 的定義可以是這樣的:

contentRender (h, data) { 
   return (<div>Current Data: {data['app']}</div>); 
},

總結

render 真的很有趣,其實際上就是jquery 時代的 創(chuàng)建dom,構建dom tree 的過程,但是更加的智能化、更優(yōu)雅。 掌握了render ,就可以自由構建可復用的組件容器。建議詳細閱讀官方文檔,非常有用。

一些思考:

開發(fā)一個前端項目,不僅僅是視圖和組件邏輯,更重要的是數(shù)據(jù)服務,現(xiàn)代化前端幾乎都是數(shù)據(jù)驅動的。因為一個app 在組件初始化時完成了數(shù)據(jù)和視圖綁定,對視圖的監(jiān)聽,隨著app 的運行,實際上是不斷變化的數(shù)據(jù)在驅動視圖的變化。

基于MVC 的架構或 MVVM的架構,在不斷寫組件的過程中,我們不斷反思該如何寫一個組件,怎么把多個組件集成到一個復雜組件中,組件中的邏輯部分是否應該合理拆分出其他幾個通用的模塊/類。

比如api service 單獨處理api相關的,api service 里面的網(wǎng)絡請求有可以單獨出 network 層,為了方便替換net 請求庫,還有許多通用的數(shù)據(jù)格式轉換層,都是可以單獨成類或者service的概念。

參考文章:
官方文檔:渲染函數(shù) & JSX
支持 jsx 語法的插件,transform-vue-jsx
被誤解的MVC和被神化的MVVM,rethinking-mvc-mvvm

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

相關閱讀更多精彩內容

友情鏈接更多精彩內容