閱讀495 返回首頁    go 阿裏雲 go 技術社區[雲棲]


aform — 工業級表單解決方案

aform的誕生已經有些年頭了,當時起源於團隊有時會承載一些表單的開發,比如一些數據列表錄入界麵,一些開關的配置,另外還有一些場合需要動態表單,發現當時市麵上表單引擎非常少,一些工作流係統自帶表單引擎,但功能有限,相反,表單的皮膚庫、控件庫、校驗庫倒是很多,但在表單開發模式上並沒有一套比較簡便和完整的框架。

因此我打算自己做1個表單引擎,作為一個懶人,我首先想到的就是不用再寫html了,隻要有一份json數據,我自動生成表單,比如發現是字符串,我生成text field,數字生成number控件,對象生成fieldset,數組生成table,而且是需要支持嵌套;

另外一點就是表單的取數,當時大部分表單取數還是需要自己編寫代碼的,比如要取checkbox的選中態,你需要自己去遍曆被勾選的checkbox,jquery盡管提供了一個serializeForm的方法,然而它不支持層級的嵌套以及組件的封裝,所有的input會打平成一個kv對象,這僅適合非常簡單的場景,我希望這個表單框架能實現用什麼結構來渲染,那麼也可以自動取到其表單數據,且結構也和渲染時數據保持一致。

因此,aform的最初版本就是這樣1個東西,即根據json生成表單,再調用取數方法獲取一致的json結構,如圖所示:

可別小看這麼一個小功能,單就表單嵌套和數組自動生成這一塊已經超越大部分專業的工作流係統使用的表單引擎了,而且它沒依賴任何庫,且支持各種ie瀏覽器。

但是對於真正商業使用的表單來說,僅支持表單生成和取數這塊的自動化是遠遠不夠的,aform在後續的發展過程中,逐漸支持了根據schema生成表單、基於model的校驗、自定義輸入控件、自定義指令、數據適配、數據監聽等各種機製,那麼接下來,就對aform做一個完整的介紹。

aform對表單生命周期的涵蓋

盡管表單通常是一次性的渲染,但也可以從成千上萬的表單中抽出一些公共邏輯,這就是表單的生命周期,通常涵蓋渲染前的一些數據獲取、渲染中、用戶交互(通常是數據錄入,會有一些表單聯動和校驗的邏輯),最後是表單的提交(即數據的獲取)

渲染一個aform及獲取表單數據

正如前文所述,aform會根據數據生成符合語義化的標簽,比如object生成fieldset、數組生成table,基本字段生成一個行容器及label+input組合。

aform有一套自己的schema描述表單結構,和jsonschema類似,但又有很多差異最大的差別是對type的意義不同,aform認為type是html的input的type,而jsonschema認為type是數據類型,這是由於二者的出發點不一樣,因為aform主要用於定義表單,因此會全麵像html規範靠攏,而jsonschema更加適合定義數據,但由於aform采用了一個模型驅動的思路,因此也會有數據結構定義的含義在裏麵,當然後麵你會發現,二者的schema是非常方便轉換的(如果你需要的話)。

aform的schema主要配置:

配置名 釋義 類型 默認值 範例
label 生成的label中的內容,不設置則使用字段名 字符串 空字符串 label:"年齡"
jtype js數據類型,通常無需設置,僅在需要區分對象還是數組的情況下設置,Boolean、Array、Number等 字符串 空字符串 jtype:"Boolean"
defaultValue 默認值 any 不設置 defaultValue:"Y"
tips 輸入控件右側生成的tips內容,需配合tipsTpl使用 字符串 不設置 tips:"你好"
placeholder 輸入框為空時顯示的提示文字,同html5的對應屬性 字符串 不設置 placeholder:"please input your address"
type 輸入控件類型,和html的type保持一致 字符串 text type:"select"
maxlength 輸入控件的輸入值最大長度,僅針對文本框有效 數字 不設置 maxlength:20
minlength 輸入控件的輸入值最小長度 數字 不設置 minlength:10
readonly 輸入控件是否隻讀,僅針對文本框和文本區域有效 布爾型 不設置 readonly:true
disabled 輸入控件是否禁用,效果同html元素的disabled屬性 布爾型 不設置 disabled:true
required 輸入控件是否必填,用value是否為空字符串判斷 布爾型 不設置 required:true
pattern 輸入值的校驗正則表達式,格式同html5的表單元素的pattern屬性 字符串 不設置 pattern:"\\d+"
patternErrorMsg 正則校驗失敗後的錯誤提示 字符串 不設置 patternErrorMsg:"寬度需要是一個整數"
title 鼠標移到輸入控件上時顯示的提示內容 字符串 不設置 title:"請填寫數字"
datalist 輸入控件的可選項目列表。 數組 不設置 datalist:[{value:0,text:"男",group:"分組名"}]

可以看到,aform的schema幾乎和html的input的屬性完全保持一致,這是為了減少學習成本。

當指定以local模式渲染表單時,aform將根據你的schema定義生成表單,即使渲染的數據有超出schema定義的字段:

var jf = new AForm("target",{
    schemaMode:"local",
    fields:{
        a:{label:"a",defaultValue:1},
        b:{label:"b",defaultValue:2},
        c:{
            fields:{
                c1:{defaultValue:3}
                c2:{defaultValue:4}
            }}
    }
});

jf.render()

alert(jf.getJson());//輸出{a:1,b:2,c:{c1:3,c2:4}}

表單的校驗

由於aform模型驅動的思想,因此表單校驗再也不用關心dom了,aform會在合適的時機(如input blur之後)自動校驗字段,或者在取數時校驗。

aform的校驗支持兩個維度,一個是字段級別,隻能校驗該字段的值,另一個是表單全局級別,此時可校驗整個表單json。

每一條校驗規則均可自定義校驗邏輯,如下所:

var jf = new AForm("target",{
    fields:{
        a:{label:"a",required:true},//必填校驗
        b:{label:"b",pattern:"\\d+"}//正則校驗
        c:{label:"b",validators:{//自定義校驗
            rule : function(v , input){
                return v.indexOf("https://") == 0;//以http開頭
            },
            errorMsg:"字段b需以http開頭"
        }}
    },
    validators:{//全局校驗器
        rule : function(json){
            return json.a > json.b;
        },
        errorMsg:"字段a的值應該大於b的值"
    }
    });

校驗規則的函數可以提前注冊,實現模塊化管理,如:

//長度校驗
AForm.registerValidator("100length", {
rule: function(v, input) {
    this.errorMsg = "字符長度不能超過100,當前為" + v.length;
    return v.length <= 100;
},
errorMsg: ""
});

//使用已注冊的校驗器
var jf = new AForm("target",{
fields:{
    a:{label:"a",validators:["100length"]},//數組元素即驗證器名
}
});

字段異常均會拋出事件,可以監聽invalid事件從而實現輸入提醒。

自定義輸入控件

當html的默認輸入控件不夠用了或者你嫌棄它不好看,那麼此時可以定義一些自定義控件,一個自定義控件的協議包含3個方麵:

  1. render - 返回一個html字符串
  2. renderComplete - 處理render後mount到dom的邏輯,如事件交互
  3. getValue - 處理取數

實例:

//基類控件
AForm.registerControl("date",  {
desc:"date",
render: function(k, v, conf, i, af) {
    return "我是date";
},
getValue: function() {
    return "my value";
}
});

//子控件
AForm.registerControl("datetime", "date", {
desc:"datetime",
render: function(k, v, conf, i, af) {
    var html = this.__super.render.call(this ,k, v, conf, i, af);//this.__super 為父類對象
    html += " -- datetime";
    return html;
}
});

自定義屬性

到後麵,你會發現,aform自帶的那些配置已經不夠滿足表單的需求和個性化的業務邏輯,因此需要實現一套機製,可以擴展aform的屬性,這裏參考了angular的思路,但實現機製有很大差別這裏不贅述,aform的自定義屬性,可以實現對表單的幹預,比如想定義個minlength的屬性,它要求字段需要有最少輸入字符,那麼通過自定義屬性可以這麼實現:

AForm.registerProp("minlength", {
    beforeRender: function(conf) {
        if (!conf.minlength) {
            return;
        }
        conf.ctrlAttr["minlength"] = conf.minlength;
        conf.validators.push({
            rule: function(v) {
                return v.length >= conf.minlength;
            },
            errorMsg: "輸入的字符長度需不少於" + conf.minlength
        });
    }
});

作為表單整體解決方案的aform

aform體係龐大,本文無意介紹各個方麵,有興趣的同學可以去這裏看文檔:https://apm.alibaba-inc.com/package/@alife/aform , 事實上,aform在基礎平台支撐各種業務的過程中,已經發展成一整套解決方案,從表單設計器、表單數據web service以及組件生態圈,都有觸及,並且在各種業務線上活躍。

aform designer致力於實現表單的在線構建,目前已在部分招商入駐應用使用,它能實現表單的分步驟構建,看下截圖:

ui構建最終得到一個aform schema,前端通過web service讀取到該schema並渲染表單,aform還提供了一個數據服務供表單業務保存數據,後端可通過hsf消費前台提交的數據,整個鏈路如下圖所示:

在近2年的期間,aform形成了豐富的表單控件庫,如圖片上傳、日期選擇、類目選擇、地址選擇器等近30個組件和自定義指令,由於aform自定義控件主要是規定了協議,因此它們仍然是複用了更為基礎的組件,並沒有多做什麼輪子。

在表單監控方麵,借助everlog自定義上報係統,實現了更為細致的表單行為監控,如監控表單填寫的耗時,表單頻出錯字段,以下是一個示例:

結語

在非框架體係下,aform是強有力的解決表單開發效率的利器,盡管react和mvvm庫在解決表單開發效率上有一些進步,但並沒有係統性和針對性的解決方案,由於aform沒有依賴任何庫,因此可極為簡易地引入到現有的技術體係,當然它也是有缺陷的,比如暫不支持表單的聯動(估計快了),aform目前已經應用到上百個表單,涵蓋部分後台boss係統、1688招商報名、實力商家及源頭好貨的入駐、jdata的動態表單等業務,它是非常可靠的。

在未來,aform仍將作為一個非框架體係下的表單解決方案而存在,在中台dpl和react大背景下,aform會和國際站以及更多的表單領域融合,形成全新的react體係下的表單解決方案,共建集團表單大中台。

最後更新:2017-10-24 19:33:58

  上一篇:go  將zabbix 監控圖以圖片格式發送郵件到管理員郵箱
  下一篇:go  初識weex與rax