上一篇說了項目搭建和結構,這篇說說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í)行時機

還是得把組件的生命周期搬出來,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