Vue 表單讀寫分發器 —— 編輯/詳情 的合併解決方案

最近我對我公司前端開發過程當中的一個痛點,寫了一個開源項目,分別對 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>
複製代碼

使用分發器比較使用表單只多了三步:

  1. 添加 provide 屬性,其中 rwDispatcherProvider 的值指向自身

  2. data屬性中添加 rwDispatcherState 作狀態管理(read or write)

  3. 原來表單元素的標籤加一個 -dispatcher 後綴,其它配置與表單組件保持不變


這樣就完成了表單到分發器的代碼遷移,咱們這樣理解它:

編輯頁用表單組件實現,是狀態;

詳情頁不能編輯,因此是狀態。

那麼,將表單組件替換成分發器,用狀態參數管理讀和寫。若是是寫狀態,分發器將組件渲染成表單組件,若是讀狀態,分發器將組件渲染成詳情組件。這樣就實現了一套代碼維護編輯和詳情兩個頁面。

王婆賣瓜,自賣自詡。爲何要推薦分發器,主要它有如下幾個特色:

  • 支持多個組件庫

element-uiiview 都有對應的分發器。

  • 使用簡單

只多了三步。

  • 徹底定製化

提供多種配置,根據項目的實際須要自由定製渲染函數。

應用

說到這裏,到底有哪些地方能夠用到它呢?我總結了一下,大概有如下場景

  • 一套代碼實現表單的編輯和詳情(預覽)功能

編輯和詳情

  • 在表格中雙擊單元格直接編輯

編輯單元格

  • 在卡片中直接切換到編輯狀態

卡片

實現原理

分發器的實現原理是 vueprovide/inject渲染函數

各分發器根據 provide 的狀態參數,進入對應的渲染函數,實現對應的渲染邏輯。有興趣的同窗能夠去 github 上看看源碼,若是以爲對本身有幫助的,歡迎 start(*^-^*),謝謝!

如下是其餘相關連接:

文檔

element-ui 分發器示例

iview 分發器示例

思考

渲染函數有兩個參數 (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 立刻就要來了,到時再寫一版吧,哈哈。

相關文章
相關標籤/搜索