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

青雲技術社群發表於2021-08-20
編者寄語:本期為大家帶來基於 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 貢獻程式碼。

作者

段國偉、汪曦

相關文章