上一篇說了專案搭建和結構,這篇說說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執行時機
還是得把元件的生命週期搬出來,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的概念。
參考文章: