1. 程式人生 > >基於Ant Design Vue封裝一個表單控制元件

基於Ant Design Vue封裝一個表單控制元件

# 開原始碼 [https://github.com/naturefwvue/nf-vue3-ant](https://github.com/naturefwvue/nf-vue3-ant) > 有缺點本來是寫在最後的,但是博文寫的似乎有點太長了,估計大家沒時間往下看,於是就把有缺點寫在前面了,不喜歡可以先跳過。 # 缺點 靈活性肯定是沒有了,封裝的還是有些過度,靈活度大大降低,沒有使用slot,想加點啥目前是不可能的,等以後需要了再說,畢竟這個專案才剛剛開始。 (為啥缺點只有一條?那不那啥嗎,基於ant design vue封裝的,他們都那麼強大了,還能有啥缺點?封裝後除了失去靈活性還能差啥?) # 優點 1. 簡潔,程式碼很少,做好meta就可以了,另外meta也不需要手寫,有個小工具可以輔助建立。 2. 風格統一,程式碼就是這樣,當需要寫新的表單的時候,也不需要複製貼上,只需要弄個meta就行了,想變風格都變不了。 3. 可以統一修改升級。UI版本升級了,VUE版本升級了,咋辦?改一下元件內部程式碼即可,呼叫元件的程式碼並不需要修改。這樣還怕升級了嗎? 4. 可以跨UI,甚至跨框架。之前看了一下element,本來想用的,但是不支援vue3.0只好作罷。element的使用方式也是大同小異,那麼我基於element也封裝一套元件,保證外部使用方式一致,那麼是不是可以做到UI隨便切換了呢? 5. 便於專案升級。專案打包釋出後,如果需求有變更,一般修改完後需要重新打包釋出。而我們的專案是通過 meta 來控制表單的,也就是說如果有變動,那麼改json檔案即可,而json可以通過ajax來載入,不用打包到專案裡面。 # 為啥還要封裝 > ant design vue 都已經提供那麼的元件了,還不夠用嗎?為啥還要折騰 首先antdv 是一個非常強大UI庫,提供了很強大的功能和漂亮的UI,使用方面也是非常的靈活,不僅有Form表單,還有各種Data Entry元件,非常靈活。只是魚和熊掌不能兼得,antdv為了靈活而犧牲了一些簡潔性。 ## select 比如a-select,官網程式碼如下:(有刪減) ~~~
~~~ ~~~ ~~~ 首先要設定一些屬性,然後還要逐行設定 a-select-option,是不是有點麻煩? ## form 再來看一下form的官網示例:(七個欄位的簡單表單) ~~~
~~~ ~~~ ~~~ 在Form表單裡面也是這樣的設定方式,而表單裡面有很多各種各樣的控制元件,一個一個寫起來實在是太累。看這樣的程式碼有點眼暈,似乎也不太便於維護,不知道大家是怎麼編寫和維護的。 大家都知道我很懶,我想用v-for來做表單,這樣即使一百個欄位也是一個for搞定,這樣程式碼就簡單多了。 那麼如何實現呢? # 如何封裝? vue的思路就是——資料驅動,那麼我就把這個思路做的更徹底一點,——**讓資料驅動dom的屬性** ## 統一標籤名稱 想要for迴圈,標籤必須統一,a-input、a-select等等都不一樣,這還怎麼迴圈?所以要先做一個統一的元件,以便於for迴圈。然後內部再分為多種不同的元件,這樣便於維護,要不然程式碼都寫到一起就太亂了。 於是結構就是這樣: 結構圖 ![](https://img2020.cnblogs.com/blog/17148/202009/17148-20200917192515098-262574940.png) ## 統一屬性 除了標籤之外,屬性也要一致,否則還是不能for。那麼怎麼辦呢?不同的控制元件需要的屬性都不一樣呀,這個好辦,我們整合成兩個就行 ### v-model value 這個必須單獨拿出來。 ### meta 其他的屬性都統一放在這裡,把這個東東傳遞進去就好,然後內部識別領取自己的屬性。這樣就搞定了。 # 程式碼 我們來看meta的結構。 ## meta 以input為例,其他都大同小異 ~~~ props: { modelValue: String, meta: { type: Object, default: () =>
{ return { controlId: Number, // 編號,區別同一個表單裡的其他控制元件 colName: String, // 欄位名稱 controlType: Number, // 用型別編號表示type isClear: { // 連續新增時是否恢復預設值 type: Boolean, default: false }, defaultValue: String, // 預設值 autofocus: { // 是否自動獲得焦點 type: Boolean, default: false }, required: { // 必填 type: Boolean, default: true }, disabled: { // 是否禁用 type: Boolean, default: false }, readonly: { // 只讀 type: Boolean, default: false }, pattern: String, // 用正則做驗證。 placeholder: String, title: String, // 提示資訊 maxlength: Number, // 最大字元數 autocomplete: { // off type: String, default: 'on' } } } } }, ~~~ 不同型別的元件,會有所調整。 ## input 模板部分 ~~~ ~~~ 先把需要的屬性,通過meta都給繫結上 js ~~~ ~~~ 這樣我們只要做好meta,就可以完全控制控制元件了。其他控制元件也是類似的思路,就不一一貼程式碼了。 ## form-Item 元件分的太零碎,使用的時候很麻煩,那麼怎麼辦呢?再做個元件整合一下。 ~~~ ~~~ 很笨的方法,挨個型別判斷。這裡使用了魔數,大概會被噴,不過早就習慣了。 ~~~ ~~~ 在這裡統一註冊各種零散的元件,使用的時候就不用想,到底要用哪種元件了。 ## 表單 好了,準備工作都做好了,我們可以開始for迴圈了。 找了半天,antdv沒有提供單純的table,只好手動找class了,於是程式碼變成了這樣。 ~~~
{{item.title}}:
~~~ > **程式碼行數和控制元件(欄位)數量無關。程式碼數量也和有多少表單無關。** 是不是看起來一點都不像一個表單?程式碼是不是少的有點可憐? nfInput 控制元件有兩個屬性v-model 和 meta,他會根據meta自動建立需要的dom,並且繫結屬性。當然實際幹活的是vue和antdv,我只是做了一種嘗試。 ~~~ ~~~ ## meta,單獨的json檔案 meta並不需要寫在程式碼裡,因為實在是太長了。可以寫在單獨的json檔案裡面,這樣便於載入。另外也可以做成ajax載入的方式,這樣專案釋出後,如何需求有變動,需要調整表單的話,那麼只需要單獨修改json檔案即可,不用重新打包釋出。 ~~~ { "companyForm":{ "1000":{ "controlId": 1000, "colName": "companyName", "controlType": 101, "isClear": true, "disabled": false, "required": true, "readonly": false, "pattern": "", "class": "", "placeholder": "請輸入公司名稱", "title": "公司名稱", "autocomplete": "on", "size": 30, "maxlength": 100, "optionList": [] }, "1001":{ "controlId": 1001, "colName": "companyCode", "controlType": 131, "isClear": true, "disabled": false, "required": true, "readonly": false, "pattern": "", "class": "", "placeholder": "公司郵編", "title": "公司郵編", "autocomplete": "on", "min": 100000, "max": 999999, "step": 1, "maxlength": 6, "optionList": [] }, "1002":{ "controlId": 1002, "colName": "legalPerson", "controlType": 101, "isClear": true, "disabled": false, "required": true, "readonly": false, "pattern": "", "class": "", "placeholder": "請輸入法人姓名", "title": "法人", "autocomplete": "on", "size": 20, "maxlength": 50, "optionList": [] }, "1003":{ "controlId": 1003, "colName": "liaisonMan", "controlType": 101, "isClear": true, "disabled": false, "required": true, "readonly": false, "pattern": "", "class": "", "placeholder": "請輸入聯絡人姓名", "title": "聯絡人", "autocomplete": "on", "size": 20, "maxlength": 50, "optionList": [] }, "1004": { "controlId": "1004", "colName": "address", "controlType": 101, "isClear": true, "defaultValue": "", "autofocus": false, "disabled": false, "required": true, "readonly": false, "pattern": "", "class": "", "placeholder": "請輸入公司地址", "title": "公司地址", "autocomplete": "on", "size": 30, "maxlength": 50, "optionKey": "", "optionList": [ ] }, "1005": { "controlId": "1005", "colName": "telphone", "controlType": 103, "isClear": true, "defaultValue": "", "autofocus": false, "disabled": false, "required": true, "readonly": false, "pattern": "", "class": "", "placeholder": "請輸入公司電話", "title": "公司電話", "autocomplete": "on", "size": 30, "maxlength": 50, "optionKey": "", "optionList": [ ] }, "1006": { "controlId": "1006", "colName": "URL", "controlType": 105, "isClear": true, "defaultValue": "", "autofocus": false, "disabled": false, "required": true, "readonly": false, "pattern": "", "class": "", "placeholder": "https://www.", "title": "公司網址", "autocomplete": "on", "size": 30, "maxlength": 50, "optionKey": "", "optionList": [ ] }, "1007": { "controlId": "1007", "colName": "Email", "controlType": 104, "isClear": true, "defaultValue": "", "autofocus": false, "disabled": false, "required": true, "readonly": false, "pattern": "", "class": "", "placeholder": "@", "title": "公司郵件", "autocomplete": "on", "size": 30, "maxlength": 50, "optionKey": "", "optionList": [ ] }, "1008": { "controlId": 1008, "colName": "type", "title": "公司型別", "controlType": 190, "isClear": true, "defaultValue": "", "autofocus": false, "disabled": false, "required": true, "pattern": "", "class": "", "optionList": [ { "value": 1, "title": "有限責任公司" }, { "value": 2, "title": "股份有限責任公司" }, { "value": 3, "title": "個人獨資企業" }, { "value": 4, "title": "合夥企業" }, { "value": 5, "title": "個體工商戶" } ] }, "1009": { "controlId": 1009, "colName": "createDate", "controlType": 140, "isClear": true, "defaultValue": "", "autofocus": false, "disabled": false, "required": true, "readonly": false, "pattern": "", "class": "", "title": "成立日期", "min": "1910-01-01", "max": "2999-12-31", "step": 1 } } } ~~~ 資料和程式碼分離,是不是很完美。 # 為啥不直接用antdv提供的 Form 表單? 這個嘛,思路不太一樣。好吧,其實是官網的程式碼,在本地還沒有除錯成功,等研究明白了還是會用的。