基於 Formily 的表單設計器實現原理分析 ​

語言: CN / TW / HK

編者寄語:本期為大家帶來基於 Formily 的拖拽式表單設計器玩法,探索可視化時代表單設計器的可能。

背景

在控制枱類 web 應用中,表單是最常見的交互形式。用户在表單中填寫信息,點擊提交就能完成對數據創建或者修改操作。

最開始,前端開發人員根據業務模型和具體需求,通過逐一編寫或者聲明實現表單中的各個字段,測試通過之後發佈上線。漸漸地,開發人員開始把一些常用的方法抽象成表單庫複用,提升開發效率。隨着業務複雜度的增加和需求的不斷演進,對錶單的展示形式和靈活程度要求也在不斷提高,現有的表單庫只能解決部分問題,開發者仍需花費大量的精力在更新表單字段或者開發新表單上。

那有沒有一種方式,既能讓開發人員快速構建表單,同時在後期又很少或者根本不需要開發人員介入來更新表單呢?

此時,表單設計器應運而生。表單設計器提供了可視化界面,讓非專業開發人員也能通過拖拽的方式,所見即所得的構建業務所需表單。

表單設計器樣式

目前很多開源的表單設計器實現,在 UI 上都大同小異,設計器的結構類似設計軟件的佈局。表單設計器一般為左中右三欄佈局:

  • 左側是控件列表,列出了設計器支持的表單控件。

  • 中間部分是畫布(canvas),左側的控件可直接拖拽到畫布中,並支持控件調整順序、複製等操作。

  • 右側是表單字段的配置區域,在畫布中選中一個字段,右側將展示此字段的所有屬性,用户可在此處配置字段標題、描述、校驗規則等。

file

原理解析

表單設計器的輸出是一份描述表單字段的 JSON Schema,表單設計完成後 JSON Schema 將直接存儲到後端。表單發佈後,前端再根據 JSON Schema 渲染表單。表單中所有字段的信息都是存儲在 Schema 中,所以每次對錶單的更新都是修改 Schema 中的內容,無需傳統的編譯過程。藉助表單設計器,不但將開發人員從應對業務變更的頻繁改動中解放出來,同時大大提高了非專業開發人的生產力,減少了溝通成本。

JSON Schema 是表單設計器和表單渲染組件之間溝通的語言。要理解表單設計器的核心,首先要理解 Schema。在實際的項目中,JSON Schema 一般比較複雜,此處不做展開。本文的主題是表單設計器的實現原理,主要關心的是如何提供一個可視化界面,讓用户能夠快速生成 Schema,Schema 的詳細格式將在後續文章中介紹,這裏先提供一個簡化版本的定義:

	interface Schema {
		fields: Record<FieldKey, FieldSchema>;
	}
	​
	interface FieldSchema {
		title: string;
		type: 'string' | 'object' | 'array' | 'number' | 'boolean';
		component: string;
		componentProps: {
			[name: string]: any;
		};
	}

眾所周知,表單由多個 input 控件組成,input 控件包含多種形式,如:文本、數字、單選和多選等。Schema 中除了描述字段對應的是哪種類型的 input 外,還需要描述控件的行為,例如是否限制輸入長度、是否必填等。有了這些描述後,表單渲染組件才能根據 Schema 渲染出符合預期的表單。 在上面的類型定義中:

  • component 表示該字段用什麼 input 組件渲染。

  • componentProps 表示傳給組件的 props,用於控制組件的行為。

  • type 表示組件接受和期望返回的數據類型。

  • FieldKey 是字段在表單中的唯一標識,用户側不透出。

  • title 表示表單中字段對應的 label,它的值用户可讀。

表單設計器的任務就是從零開始,或者將已有的 JSON Schema 作為輸入,對 Schema 中的字段做添加、刪除和更新操作,最後輸出 Schema。如果我們把表單設計器看成一個整體,那它的功能可以用下圖表示:

file

進一步講,我們可以將上圖拆分到控件級別,以一個字段的配置作為輸入,經過更新後重新輸出這個字段的配置。

file

整體來看,表單就是對每個控件的操作進行組合,組合的結果就是完整的 JSON Schema。

為了能夠實現對錶單字段的修改,我們在表單設計器中提供了字段配置區域,用户在配置區域中,可以通過可視化方式定義字段屬性,而無需關心 Schema 的具體格式。表單設計器負責將配置值轉化成 Schema,同時也負責將 Schema 轉化成配置值,用來回顯配置後的頁面表單。

説明: 配置區域其實也是一個表單,每種類型的控件也都有自己特定的配置表單。 想要完成上述功能,每種控件都需要實現兩個方法:toConfig 和 toSchema。這裏用一個公式來表示這兩種方法和 Schema 的關係,其中 configValue 用來給配置表單做回顯。

	FieldSchema => toConfig => configValue => toSchema => FieldSchema

釐清了上述思路之後,我們再回到表單設計器的 UI 呈現上來。

file

左側是設計器支持的控件列表,根據上面的分析,每個控件都需要提供控件名稱、配置表單、toConfig 和 toSchema 這四個接口的實現。中間的 canvas 負責展示 Schema 中的控件,同時需要處理用户的點擊和拖拽事件。當用户點擊 canvas 中的某個字段時,右側的配置區域需要找到對應的配置表單並渲染出來。

總結

以上是表單設計器最核心的架構實現,還有一些實現上需要考慮的細節,如表單 Schema 定義解析等將在後續的文章中逐步闡述,請大家持續關注。

全象雲低代碼平台的表單設計器就是基於 Formily 實現的。Formily 的靈活擴展能力和為業務而生的特性讓我們欽佩,感謝 Formily 團隊的貢獻,希望我們後面也能為 Formily 貢獻代碼。

作者

段國偉、汪曦