vue.js 實踐總結(二)Render 函式

alex2wong發表於2018-07-18

上一篇說了專案搭建和結構,這篇說說vue 的render 函式,比較核心的概念。去年寫過一點react,所以知道render 函式是用來建立虛擬dom 的,那個時候寫 jsx 還是不亦樂乎的。列出幾個問題作為這篇的結構:

  • render 函式的作用?
  • 元件中的render 函式什麼時候執行?
  • 什麼時候需要在元件中寫 jsx ?

常遇到這個問題:

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

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

render 的作用

render 函式實際上是template 的底層方法,通過呼叫createElement(h)來建立dom節點,實際上作用就是負責元件檢視渲染的!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>
    );
}
複製程式碼

從生命週期出發,render執行時機

與render 相關的生命週期

還是得把元件的生命週期搬出來,created 鉤子函式是元件injection和reactivity 屬性初始化後,比如props、data 初始化,後面關鍵的:如果有template,則把檢視編譯為render function,如果沒有則直接呼叫被override 的render 方法建立虛擬dom節點,並且把元件對應的 htmlElement 替換為 元件的dom 結構和資料,最後觸發mounted 鉤子。

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

什麼時候需要定義render

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

我們把panel 的render 函式改為可以接受外部函式:

render(h) {
    let contentNode = (<div>default content</div>);
    if (this.contentRender && this.contentRender instanceof Function) {
      contentNode = this.contentRender(h, this.data); 
// 把資料用外部函式來渲染成使用者想要的結構
    }
    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 時代的 建立dom,構建dom tree 的過程 實際上是生成VNode 虛擬DOM節點的過程,VNode 可以被vue.js 對映為真實的DOM tree。 掌握了render ,就可以自由構建可複用的元件容器。建議詳細閱讀官方文件,非常有用。

一些思考:

開發一個前端專案,不僅僅是檢視和元件邏輯,更重要的是資料服務,現代化前端幾乎都是資料驅動的。因為一個app 在元件初始化時完成了資料和檢視繫結,對檢視的監聽,隨著app 的執行,實際上是不斷變化的資料在驅動檢視的變化。

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

比如api service 單獨處理api相關的,api service 裡面的網路請求有可以單獨出 network 層,為了方便替換net 請求庫,還有許多通用的資料格式轉換層,都是可以單獨成類或者service的概念。

參考文章:

官方文件:渲染函式 & JSX

說說 VNode 節點

支援 jsx 語法的外掛,transform-vue-jsx

被誤解的MVC和被神化的MVVM,rethinking-mvc-mvvm

相關文章