低程式碼之光!輕量級 GUI 的設計與實現

敘帝利發表於2023-12-29

前言

每當提起低程式碼,很多人都會下意識的出現過激反應,吐槽低程式碼都是**,唯恐避之不及。可能大部分人覺得低程式碼就是替代手寫程式碼,對於程式設計師來說這是不可接受的。其實低程式碼表述的含義非常寬泛,我相信很多人可能都在低程式碼平臺中受益過,而且確實可以提升效率。像原型工具(Figma)、建站平臺(WebflowFramer)、BI 報表(Power BILooker Studio)、3D 模型搭建(SplineWomp)、動畫編輯器(Rive)等等,這些都是非常有名的一些線上工具。

言歸正傳,本文並不是為了介紹低程式碼平臺,也不想評價低程式碼的好壞,只是想聊一聊低程式碼平臺中 GUI 的設計思路和實現方式。

Acrodata GUI 是一款適用於低程式碼平臺的輕量級 GUI 庫,現已開源。

GitHub: https://github.com/acrodata/gui
Playground: https://acrodata.github.io/gui/playground

什麼是 GUI

GUI 翻譯為圖形使用者介面,是指採用圖形方式顯示的計算機操作使用者介面。在前端程式設計中,我們一般很少使用 GUI 這樣的描述,所以很多人會錯誤地認為 GUI = UI library。

那麼到底什麼是 GUI 呢?為了便於理解,我們可以參照前端專案中比較有名的 GUI 專案 dat.gui。做過 3D 視覺化或者熟悉 ThreeJS 的朋友一定非常熟悉這個庫。dat.gui 的主要用途就是將配置項轉換成圖形化控制元件,方便除錯引數。

除了 dat.gui 之外,還有其它幾款 GUI 專案也做得不錯,tweakpanelil-guileva

低程式碼平臺中的配置欄

對於使用過低程式碼平臺或者開發過類似產品的朋友來說,低程式碼平臺的佈局已經司空見慣,在佈局的右側通常都是配置欄。當然,我們使用的很多軟體也是如此。隨便貼幾張主流工具的截圖。



首先說一點,並不是每一款低程式碼產品都需要 GUI 生成配置,比如第一張截圖 Webflow,它的所有元件的配置項都是一樣的(全部是 CSS 的視覺化配置),這種情況直接寫一個公共元件可能更簡單。

但是像第三張截圖 Looker Studio 這樣的產品,每一種圖表元件的配置都不一樣,同時還允許使用者自定義元件,那麼這類產品就非常需要一套靈活易用的 GUI 庫了。

在 Acrodata GUI 的文件站首頁,我用 GUI 建立了一個稍微複雜的 CSS 漸變生成器,它和低程式碼平臺中的配置欄非常型別,歡迎把玩嘗試。

👉 檢視 CSS 漸變生成器原始碼

輕量級 GUI 的設計思路

由於低程式碼平臺的特殊性和複雜性,GUI 庫在設計的時候必須要保證能組合出任意資料結構,同時還要簡單易用。

基於 JSON 的配置項

為了支援自定義元件,GUI 庫更適合採用 JSON 資料進行配置。這和上面提到的 GUI 庫在使用上有很大的不同,我們以 dat.gui 和 Acrodata GUI 為例說明。

假設某個元件的配置項如下:

const options = {
  content: 'Hello world',
  opacity: 0.3,
  visible: false,
}

dat.gui 的用法如下:

const gui = new dat.GUI();

gui.add(options, 'content');
gui.add(options, 'opacity', 0, 1).step(0.1);
gui.add(options, 'visible');

雖然 dat.gui 的用法很簡潔,但是這種函式式的宣告方式並不適合動態元件,同時也不利於資料儲存。

而在 Acrodata GUI 中的用法則是這樣的:

<gui-form [config]="config" />
const config = {
  content: {
    type: 'text',
    name: 'content',
    default: 'Hello world'
  },
  opacity: {
    type: 'slider',
    name: 'opacity',
    min: 0,
    max: 1,
    step: 0.1,
    default: 0.3
  },
  visible: {
    type: 'switch',
    name: 'visible',
    default: false
  },
}

上面的 GUI 的配置項和元件的配置項的結構是一樣的,只需要將 options 中每個欄位的值轉換成 UI 控制元件的 JSON 宣告即可。

👉 檢視更多基礎控制元件示例

巢狀的資料結構

如果要保證 GUI 可以生成任意資料結構,需要設計五種基礎資料(string, number, boolean, object, array)的 JSON 配置項的定義格式。上面的例子中已經展示了三種基本資料型別的定義方式

在 Acrodata GUI 中 object 的定義如下:

{
  "size": {
    "type": "group",
    "name": "Size",
    "children": {
      "width": {
        "name": "Width",
        "type": "number",
        "default": 1920,
        "suffix": "px"
      },
      "height": {
        "name": "Height",
        "type": "number",
        "default": 1080,
        "suffix": "px"
      }
    }
  }
}

最後一種陣列型別是最複雜也是最繁瑣的。常用陣列包含基本資料陣列和物件陣列,同時每種陣列還要支援陣列項的動態刪減。

下面是一個可動態刪減的物件陣列的定義方式:

{
  "series": {
    "type": "tabs",
    "name": "Series",
    "default": [
      { "id": 1, "name": "bar" },
      { "id": 2, "name": "foo" }
    ],
    "template": {
      "name": "No.<%= i + 1 %>",
      "children": {
        "id": {
          "type": "number",
          "name": "ID"
        },
        "name": {
          "type": "text",
          "name": "Name"
        }
      }
    }
  }
}

如果物件陣列的陣列項不相同,則必須搭配 tab 型別來定義:

{
  "misc": {
    "type": "tabs",
    "name": "Misc",
    "children": [
      {
        "type": "tab",
        "name": "Full Name",
        "children": {
          "firstName": {
            "type": "text",
            "name": "First Name",
            "default": "James"
          },
          "lastName": {
            "type": "text",
            "name": "Last Name",
            "default": "Bob"
          }
        }
      },
      {
        "type": "tab",
        "name": "Contact",
        "children": {
          "phone": {
            "type": "text",
            "name": "Phone",
            "default": "5550100"
          }
        }
      }
    ]
  }
}

👉 檢視更多組合控制元件示例

有了上述五種基礎控制元件之後,透過巢狀組合就可以生成任意資料結構了。

JSON Schema 的侷限性

為什麼不使用 JSON Schema 呢? 很多人可能覺得使用 JSON Schema 定義 JSON 資料會更規範也更通用。這種想法是有道理的,但是 JSON Schema 也有一定的侷限性。

首先 JSON Schema 只能定義欄位的資料型別,但是無法定義欄位的 UI 型別,所以部分使用 JSON Schema 的動態表單方案還會加上 UI Schema,比如 react-jsonschema-form

另外 JSON Schema 的格式較為複雜,元件的配置項與 JSON Schema 的對映關係非常不直觀。

基於響應式表單構建 GUI

Acrodata GUI 是基於 Angular 的響應式表單構建的,核心程式碼只有大約 200 行(檢視原始碼)。

為了方便在模板中遍歷資料,首先需要將 GUI config 物件轉換成陣列,同時使用響應式表單的 registerControlFormGroup 的例項中註冊所有表單控制元件。然後在模板中使用響應式表單的指令 formGroupNameformControlNameformArrayName 繫結不同 type 的控制元件就可以了。

Acrodata GUI 使用 Angular Material 作為基礎元件庫,所有樣式和元件都是分模組匯入,所以不會產生冗餘的程式碼,其它元件庫也可以使用。

開始使用 GUI 元件

<gui-form [config]="config" [model]="model" [form]="form" />

config 表示 GUI 的 JSON 配置項,不同型別的控制元件的配置項稍有不同,詳見文件。除了使用 default 定義控制元件的預設值之外,也可以使用 model(表單值,等同於元件的配置項 options)來定義或更新表單的預設值,這得益於 Angular 響應式表單的 patchValue 方法。

如果你需要監聽表單的狀態或者值變更,可以使用 form 引數,它可以追蹤表單的所有狀態變化。

form = new FormGroup({});

this.form.valueChanges.subscribe(v =>{...});
this.form.get('opacity').valueChanges.subscribe(v =>{...});

總結

雖然上面展示的 GUI 功能很強大,但是 GUI 和動態表單並不能完全劃等號,也不是所有的配置項都適合使用 GUI。因為 GUI 的控制元件型別有限,而且其本身沒有複雜的邏輯,所以在低程式碼平臺中要有取捨的使用 GUI 配置。

如果你喜歡 Acrodata GUI 或者有更好的想法,歡迎和我交流!

相關文章