【實戰(zhàn)】如何設(shè)計動態(tài)化表單
本文首發(fā)于政采云前端團隊博客:ZooTeam 拍了拍你,來看看如何設(shè)計動態(tài)化表單
https://www.zoo.team/article/dynamic-form

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

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

備選組件面板
容器組件——是用來存放基礎(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)該是不同。這部分下文組件屬性部分會詳細說明
拖拽面板
具體實現(xiàn)方案采用的是 React-DnD。
組件配置
[{
label: '是否可見',
code: 'visible',
widget: 'switchBtn',
initialValue: true
},
{
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)的值。
容器屬性 共有的屬性有標(biāo)題、編碼、是否可見、以及容器結(jié)構(gòu)是否對數(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)題,編碼,是否可見,是否必填等屬性都是基本屬性。組件屬性則是組件私有的屬性。


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

交互規(guī)則 表單交互規(guī)則在表單級別綁定,而不是在字段級別。進行就近配置的目的,是為了方便管理,進入一個表單配置,該表單的交互在右側(cè)一目了然。
接口綁定 則是表單渲染過程中有可能涉及到一些遠程數(shù)據(jù)的讀取,比如默認值等。這部分數(shù)據(jù)的配置需要用到遠程數(shù)據(jù)。表單上綁定了接口之后,表單初始化之前先發(fā)請求獲取綁定接口的數(shù)據(jù),相應(yīng)的表單組件里就可以使用到該數(shù)據(jù)進行初始化。
管理端數(shù)據(jù)流轉(zhuǎn)

表單動態(tài)渲染
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>
);
}
}
待完善
自定義組件的異步加載。當(dāng)一個表單需要新增加一個自定義組件時,項目需要重新構(gòu)建發(fā)版。如果自定義組件可以單獨發(fā)布,就可以做到及時添加一個自定義組件,不需要項目重新構(gòu)建發(fā)布了。當(dāng)然如果自定義組件太多,異步加載還是會有些性能問題。而這就需要做到同頁面下多組件代碼合并了
一些配置的沉淀復(fù)用。比如某些經(jīng)常配置的表單塊。可以沉淀為常用組件。直接選擇使用,可進一步簡化配置流程
同頁面下的一些相同區(qū)塊,如果每個頁面都單獨維護,會極大的增加維護成本、抽取并聯(lián)動,可以極大的減少維護表單的成本
展望
對于管理端流轉(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í)成長
