最近我對我公司前端開發過程當中的一個痛點,寫了一個開源項目,分別對 element-ui 和 iview 的表單組件作了一層擴展,想介紹給你們,望多多支持。html
咱們公司作的是 to B
的項目,框架選定的 Vue
。與互聯網 to C
項目比,to B
以管理後臺爲主,沒有太多複雜的交互,基本都是頁面的增刪改查,惟有一點就是量大!量大!量大!例如咱們有一種場景須要實現表單的編輯功能。場景地址前端
很簡單,這個頁面用 element-ui
的表單組件就能完成。而後又須要一個表單的詳情功能。vue
上面的編輯頁和詳情頁,除了一個用來編輯,一個用來展現,其餘都是同樣的。編輯頁用 element-ui
開發,詳情頁咱們還需再開發一套,按照這種開發模式,就會有下面的問題:git
編輯頁須要寫一遍,詳情頁也須要寫一遍,即兩遍。github
編輯頁是現成的表單組件,不須要寫樣式,詳情頁須要從新寫一遍,並且風格要和表單組件保持一致。element-ui
咱們這邊一個前端項目大概有 20 到 40 組這樣的頁面,而一個管理系統由 10 個前端項目,10 個以上的後端項目組成。因此一個完整的管理系統會有 200 組以上編輯詳情頁面。後端
呵呵,你們都懂的,需求會改動,設計也會改動。當表單項增一項或減一項,編輯頁要改一遍,詳情頁也要改一遍;當表單佈局從一行兩列改成一行三列,編輯頁要改一遍,詳情頁也要改一遍。api
一兩個頁面還好,可是 to B
項目量大!量大!量大!維護起來就很是痛苦了。bash
若是把它們寫成一個文件會不會更好呢,有同事開始動手,將編輯頁和詳情頁合併成一個文件,經過 v-if
來實現編輯和詳情的判斷,以下:框架
<el-form ref="form" :model="form">
<el-form-item label="活動名稱">
<template v-if="state='edit'">
<el-input v-model="form.name" />
</template>
<template v-else>
<div class="form-item--detail">
<label>活動名稱</label>
<div class="form-item__content">{{ form.name }}</div>
</div>
</template>
</el-form-item>
...
</el-form>
複製代碼
結果這個文件的代碼量劇增,可讀性和維護性大大下降。一兩個這樣的文件維護起來還行,試想一下成百上千個這樣的文件,那維護起來就是一場災難了。
因而我針對表單組件寫了一個擴展,暫時命名爲 組件分發器(傳送門),直接上代碼。
以 element-ui
爲例,表單(編輯頁)咱們是這樣寫的:
<template>
<el-form ref="form" :model="form">
<el-form-item label="活動名稱">
<el-input v-model="form.name" />
</el-form-item>
...
</el-form>
</template>
複製代碼
換成分發器能夠這樣寫:
<template>
<el-form ref="form" :model="form">
<el-form-item label="活動名稱">
<el-input-dispatcher v-model="form.name" />
</el-form-item>
...
</el-form>
</template>
<script>
export default {
provide () {
return {
rwDispatcherProvider: this
}
},
data () {
return {
rwDispatcherState: 'write',
...
}
}
}
</script>
複製代碼
使用分發器比較使用表單只多了三步:
添加 provide 屬性,其中 rwDispatcherProvider 的值指向自身
data屬性中添加 rwDispatcherState 作狀態管理(read or write)
原來表單元素的標籤加一個 -dispatcher 後綴,其它配置與表單組件保持不變
這樣就完成了表單到分發器的代碼遷移,咱們這樣理解它:
編輯頁用表單組件實現,是寫
狀態;
詳情頁不能編輯,因此是讀
狀態。
那麼,將表單組件替換成分發器,用狀態參數管理讀和寫。若是是寫狀態,分發器將組件渲染成表單組件,若是讀狀態,分發器將組件渲染成詳情組件。這樣就實現了一套代碼維護編輯和詳情兩個頁面。
王婆賣瓜,自賣自詡。爲何要推薦分發器,主要它有如下幾個特色:
element-ui
、iview
都有對應的分發器。
只多了三步。
提供多種配置,根據項目的實際須要自由定製渲染函數。
說到這裏,到底有哪些地方能夠用到它呢?我總結了一下,大概有如下場景
分發器的實現原理是 vue
的 provide/inject 和 渲染函數。
各分發器根據 provide
的狀態參數,進入對應的渲染函數,實現對應的渲染邏輯。有興趣的同窗能夠去 github
上看看源碼,若是以爲對本身有幫助的,歡迎 start(*^-^*),謝謝!
如下是其餘相關連接:
渲染函數有兩個參數 (h, context),以 el-input-dispatcher 爲例,它要傳給 el-input 的數據對象 (class、style、attrs、props、on、directives、slot、ref 等等),實現代碼很是簡單:
...
render (h, context) {
const { data, children } = context
return h('el-input', data, children)
},
...
複製代碼
很順滑,因此我選擇了渲染函數,但隨着項目的深刻,發現渲染函數有些問題,最大的問題是它沒有生命週期,渲染的時候沒有辦法和其餘組件通訊,好比表單元素的 size
屬性,能夠設置在表單組件自己,若是自己沒有設置會向上找 el-form-item 上的 size 屬性,el-form-item 也沒有會繼續向上找 el-form。這個在 render 函數裏是沒有辦法經過 context.parent 實現的。
或許實例屬性能夠嘗試一下吧,vue 3.0 立刻就要來了,到時再寫一版吧,哈哈。