<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          【實戰(zhàn)】如何設(shè)計動態(tài)化表單

          共 6123字,需瀏覽 13分鐘

           ·

          2021-03-04 09:01

          本文首發(fā)于政采云前端團隊博客:ZooTeam 拍了拍你,來看看如何設(shè)計動態(tài)化表單

          https://www.zoo.team/article/dynamic-form


          前言

          對于 ToB 業(yè)務(wù)而言,隨著業(yè)務(wù)的不斷壯大,接入的客戶逐漸增加,相同頁面的差異化的需求越來越多,尤其是在表單層面,小到多一個字段少一個字段這種簡單的需求,大到整個頁面不變的只剩下一些基礎(chǔ)字段。
          一旦這種差異化需求隨著業(yè)務(wù)量的增長而膨脹起來。代碼中的 IF ELSE 越來越多,項目就越來越難以維護。基于這個問題,比較普遍的解決方案要么是項目拆分,要么相同項目的代碼分割。

          這兩種方案都有維護成本比較大的弊端,那么有沒有更好點的解決方案呢。本文就帶你了解一下動態(tài)化表單搭建。

          什么是動態(tài)表單

          先下個定義,動態(tài)表單是頁面根據(jù)管理端配置的不同的 Schema 結(jié)構(gòu),動態(tài)渲染出不同的表單項的表單。
          動態(tài)表單一般分兩個部分,管理端和渲染端。
          管理端配置表單項及相應(yīng)的簡單交互產(chǎn)出 Schema 數(shù)據(jù)。
          渲染端根據(jù) Schema 數(shù)據(jù)相應(yīng)的渲染出不同的表單項并實現(xiàn)簡單的交互。大致流程如下。
          圖片

          動態(tài)表單的實現(xiàn)

          表單配置

          對于 Schema 數(shù)據(jù)的配置,考慮到接入業(yè)務(wù)方的接入成本及維護成本。
          管理端采用了可拖拽式的所見即所得配置面板。這里共分為四個部分,備選組件面板,拖拽面板,組件屬性面板和表單屬性配置(視圖屬性)。
          具體實現(xiàn)如下圖:
          圖片

          備選組件面板

          左側(cè)備選組件欄里的備選組件共分三種,容器組件,基礎(chǔ)組件,自定義組件。
          • 容器組件——是用來存放基礎(chǔ)組件的組件。例如表單組件,子表單組件,表格表單組件。這些組件都是內(nèi)部可以存放其他子組件的組件。屬于容器組件。系統(tǒng)內(nèi)置了 3 個容器組件,對于中臺系統(tǒng)而言,容器組件不會太多樣化。所以容器組件沒有做自定義組件的功能。當(dāng)然后期如果需要的話也可以擴展出容器組件的自定義組件功能

          • 基礎(chǔ)組件——就是普通的表單項。系統(tǒng)內(nèi)置了 13 個基礎(chǔ)組件。這些組件都是基于 Antd 的 React 組件做的二次包裝

          • 自定義組件——業(yè)務(wù)方經(jīng)常出現(xiàn)一些個性化的表單項,例如某個輸入框后面加個鏈接跳轉(zhuǎn)之類的需求,對于這種組件,系統(tǒng)提供了自定義組件的注冊及配置功能。這樣業(yè)務(wù)方就可以自由的維護專屬于自己的業(yè)務(wù)表單組件了。同時也解放出表單系統(tǒng)維護者的時間。組件注冊同時也是一個更加輕量級的自定義組件模塊。因為不同的組件需要設(shè)置不同的參數(shù),所以該組件對應(yīng)的右側(cè)屬性表單也應(yīng)該是不同。這部分下文組件屬性部分會詳細說明

          拖拽面板

          拖拽面板就是維護組件展示關(guān)系的面板,同時提供拖拽排序、刪除、復(fù)制、預(yù)覽等功能。

          具體實現(xiàn)方案采用的是 React-DnD。

          組件配置

          屬性配置面板本身就是個更加輕量級的動態(tài)表單實現(xiàn)。
          只是 Schema 由開發(fā)者直接寫死而沒有一個可配置的頁面而已(自定義組件注冊部分例外)。
          當(dāng)在拖拽面板選中一個組件時,組件屬性配置面板會渲染出相應(yīng)組件的可配置項表單, 這里提供一下簡單的組件屬性配置面板的 Schema 供大家參考。
          [{
            label'是否可見',
            code'visible',
            widget'switchBtn',
            initialValuetrue
          },
          {
            label'是否可編輯'// 標(biāo)簽文案
            code: 'code'// 字段編碼
            widget: 'switchBtn'// 組件類型
            initialValue: true// 初始值 默認可編輯
            hide: 'exp: visible === false'// 是否隱藏
            required: true // 是否必填
          }]

          細心的同學(xué)會發(fā)現(xiàn) hide 字段寫了個表達式。這里通過 exp: 開頭作為一個表達式的標(biāo)識。表達式的可以使用的變量是屬性表單內(nèi)的值。

          比如上面這個例子,visible 是上面定義了一個是否可見的字段。如果當(dāng)前選中的這個組件不可見的話,是否可編輯本身就無從談起,所以直接隱藏掉。

          容器屬性 共有的屬性有標(biāo)題、編碼、是否可見、以及容器結(jié)構(gòu)是否對數(shù)據(jù)透明。

          前面三個好理解。容器結(jié)構(gòu)是否對數(shù)據(jù)透明是什么呢?
          前面說過,我們的容器組件是可多層嵌套的,那問題來了,數(shù)據(jù)咋辦,表單嵌套會導(dǎo)致數(shù)據(jù)也跟著嵌套。所以這里參考了阿里的 Formily 開源表單方案。使用一個 skip ,來使其對數(shù)據(jù)透明。即:
          {
            "title""表單",
            "type""form",
            "fields": [{
              "name""name",
              "label""姓名"
            }, {
              "title""子表單",
              "skip"true// 表單結(jié)構(gòu)對數(shù)據(jù)透明
              "name""item",
              "type""form",
              "fields": [
                {
                  "name""object",
                  "label""物品"
                }, {
                  "name""brand",
                  "label""品牌"
                }
              ]
            }]
          }

          skip 為 false 時返回的數(shù)據(jù)為:

          {
            "name""簡名",
            "item": {
              "object""電腦",
              "brand""Mac"
            }
          }

          skip 為 true 時返回的數(shù)據(jù)為:

          {
            "name""簡名",
            "object""電腦",
            "brand""Mac"
          }

          組件屬性 分為基本屬性和組件屬性,基本屬性是所有屬性共有的。標(biāo)題,編碼,是否可見,是否必填等屬性都是基本屬性。組件屬性則是組件私有的屬性。

          比如 Select 組件會需要一個數(shù)據(jù)來源,以及該組件是否多選之類的。基本屬性直接寫死。組件私有屬性則通過遠程數(shù)據(jù)庫維護。自定義組件的注冊就需要涉及到這部分的數(shù)據(jù)管理。
          自定義組件的注冊表單如下:
          圖片
          其中組件可配置屬性就是組件私有的屬性的定義,注冊時定義,配置該組件時賦值,渲染端渲染時應(yīng)用。可配置屬性還需要支持表達式的填寫。
          比如某個組件需要遠程數(shù)據(jù),url 提供了,但是參數(shù)需要取當(dāng)前時間,這個時候就需要組件屬性支持表達式的解析或者少量代碼讀寫運行了。
          這些屬性除了組件自定義屬性以外,還有組件默認值,組件自定義校驗,組件 onChange 事件。
          以自定義校驗為例:
          圖片

          表單屬性配置(視圖屬性)

          這部分在上圖中沒有顯示,是在組件屬性右側(cè)。表單屬性分兩部分,交互規(guī)則和接口綁定。
          圖片

          交互規(guī)則 表單交互規(guī)則在表單級別綁定,而不是在字段級別。進行就近配置的目的,是為了方便管理,進入一個表單配置,該表單的交互在右側(cè)一目了然。

          接口綁定 則是表單渲染過程中有可能涉及到一些遠程數(shù)據(jù)的讀取,比如默認值等。這部分數(shù)據(jù)的配置需要用到遠程數(shù)據(jù)。表單上綁定了接口之后,表單初始化之前先發(fā)請求獲取綁定接口的數(shù)據(jù),相應(yīng)的表單組件里就可以使用到該數(shù)據(jù)進行初始化。

          管理端數(shù)據(jù)流轉(zhuǎn)

          管理端的功能是構(gòu)建出一個目標(biāo) Schema。
          每個備選組件都有基本信息和相應(yīng)的組件可配置屬性信息。
          組件基本信息主要用于組件面板展現(xiàn)。組件可配置屬性需要在右側(cè)屬性配置時渲染成一個表單給使用者去配置,故而組件可配置信息又是一個簡化版的 Schema,這里稱為組件級 Schema。
          在拖拽頁面中添加一個組件,通過解析組件的組件級 Schema 及組件放置位置給目標(biāo) Schema 添加一個組件數(shù)據(jù)。
          然后在拖拽頁面中選中該組件,右側(cè)屬性配置會相應(yīng)渲染出組件級 Schema 所描述的表單給用戶配置填寫。用戶配置時直接修改目標(biāo) Schema 中相應(yīng)選中組件的信息。
          數(shù)據(jù)流轉(zhuǎn)圖大致如下:
          圖片

          表單動態(tài)渲染

          因為表單頁面還會有各種定制化的需求,表單渲染端這里采用組件的形式,提供了兩個組件,一個組件作為表單頁面的外層包裹組件主要功能是發(fā)請求獲取相應(yīng)的 schema.json 數(shù)據(jù)。
          另一個組件就是通過上層組件的數(shù)據(jù)渲染相應(yīng)的表單。示例:
          import { FormPageWrap, MainForm } from './index';
          @FormPageWrap({
            prefix'/api/budget'// 業(yè)務(wù)方接口前綴
            getFormParams: (props) => { // 獲取表單結(jié)構(gòu)參數(shù)
              return {};
            },
            getDataParams(props) => { // 獲取表單回填數(shù)據(jù)參數(shù)
              return {};
            }
          })
          export default class FormPage extends Component {
            render() {
              return (
                <div>
                  // 表單各種額外顯示內(nèi)容
                  <MainForm // 表單渲染組件
                    customComponent={{
                      test: TestComp,
                    }}
                    extraParams={{}}
                  />

                  // 表單各種額外顯示內(nèi)容
                </div>
              );
            }
          }
          內(nèi)部實現(xiàn)則是根據(jù) Schema 渲染相應(yīng)的組件。

          待完善

          目前系統(tǒng)部分功能還有待完善。具體有幾點:
          • 自定義組件的異步加載。當(dāng)一個表單需要新增加一個自定義組件時,項目需要重新構(gòu)建發(fā)版。如果自定義組件可以單獨發(fā)布,就可以做到及時添加一個自定義組件,不需要項目重新構(gòu)建發(fā)布了。當(dāng)然如果自定義組件太多,異步加載還是會有些性能問題。而這就需要做到同頁面下多組件代碼合并了

          • 一些配置的沉淀復(fù)用。比如某些經(jīng)常配置的表單塊。可以沉淀為常用組件。直接選擇使用,可進一步簡化配置流程

          • 同頁面下的一些相同區(qū)塊,如果每個頁面都單獨維護,會極大的增加維護成本、抽取并聯(lián)動,可以極大的減少維護表單的成本

          展望

          對于動態(tài)化表單的能力遠不止目前看到的動態(tài)表單搭建:
          • 對于管理端流轉(zhuǎn)出來的 Schema 數(shù)據(jù)可以進行二次加工,從而實現(xiàn)對于用戶的權(quán)限,業(yè)務(wù)配置等能力的擴展

          • 管理端配置出來的 Schema 不止可以用在動態(tài)表單渲染中,還可以作為數(shù)據(jù)模型去描述一個靜態(tài)數(shù)據(jù)的結(jié)構(gòu)。從而提供各業(yè)務(wù)系統(tǒng)配置數(shù)據(jù)的構(gòu)建能力

          • 前端渲染組件也不一定要和管理端的 Schema 完全耦合在一起。單獨拿來使用也是完全沒問題的,這樣對于某些簡化版動態(tài)表單的能力也能做到支持


          歡迎關(guān)注「前端雜貨鋪」,一個有溫度且致力于前端分享的雜貨鋪

          關(guān)注回復(fù)「加群」,可加入雜貨鋪一起交流學(xué)習(xí)成長

          瀏覽 276
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  久久人妻狠狠操 | 一区二区成人片18 | 日韩成人黄色 | 激情操逼视频 | 免费黄色电影在线观看 |