一個神奇的表單
表單表單卜壕,你已經長大了您旁,你要學會自己:
- 排成一列
- 排成一行
- 驗證表單數據
- 排成方隊
- 合并調整
- 動態(tài)渲染
- 支持 item 擴展組件
- 可以自動創(chuàng)建 model
實現多行多列的表單
首先感謝 el-form,真的很強大轴捎,不僅好看鹤盒,還提供了驗證功能,還有很多其他的功能侦副。
只是好像只能橫著排侦锯,或者豎著排。那么能不能多行多列呢秦驯?似乎沒有直接提供尺碰。
我們知道 el-row、el-col 可以實現多行多列的功能译隘,那么能不能結合一下呢亲桥?官網也不直說,害的我各種找固耘,還好找到了题篷。(好吧,其實折騰了一陣著的table)
二者結合一下就可以了厅目,這里有個小技巧番枚,el-row只需要一個就可以,el-col可以有多個损敷,這樣一行排滿后葫笼,會自動排到下一行。
<el-form ref="form" :model="formModule" label-width="130px">
<el-row>
<!--不循環(huán)row嗤锉,直接循環(huán)col渔欢,放不下會自動往下串行。-->
<el-col :span="8">
<!--假裝有好多好多的el-col-->
<el-form-item :label="姓名:">
<!--這里可以放組件-->
</el-form-item>
</el-col>
</el-row>
</el-form>
這樣有什么好處呢瘟忱?當然是便于我們做v-for呀奥额,給 el-col 加上 v-for 就好苫幢。
實現動態(tài)渲染功能
表單嘛,那么多字段一個一個做多麻煩垫挨,v-for 一下不香嗎韩肝?
前面封裝了那么多的組件,就是為了可以 v-for九榔。
首先準備一個json文件哀峻,里面放置需要的組件的屬性。
json比較長哲泊,我們還是看截圖吧剩蟀,直觀一些。
然后用 require 讀取進來切威,當然也可以用 axios 來讀取育特。
然后表單控件就可以用這些屬性做循環(huán)了。
另外還有幾個附帶功能:
支持單行下的合并先朦。
在單行的情況下缰冤,一些短的控件會比較占空間,我們可以把多個小的合并到一行喳魏。支持多行下的擴展棉浸。
多行的情況下,一些長的控件需要占更多的空間刺彩,我們可以設置它多占幾個格子迷郑。自動創(chuàng)建表單需要的 model。
不需要手動寫 model了迂苛。
自動創(chuàng)建 model
我比較懶三热,手擼 model 是不是有點麻煩?如果能夠自動獲得該多好三幻,于是我寫了這個函數就漾。
// 創(chuàng)建 v-model
const createModel = () => {
// 依據meta,創(chuàng)建module
for (const key in formItemMeta) {
const m = formItemMeta[key]
// 根據控件類型設置屬性值
switch (m.controlType) {
case 100: // 文本類
case 101:
case 102:
case 103:
case 104:
case 105:
case 106:
case 107:
case 130:
case 131:
formModel[m.colName] = ''
break
case 110: // 日期
case 111: // 日期時間
case 112: // 年月
case 114: // 年
case 113: // 年周
formModel[m.colName] = null
break
case 115: // 任意時間
formModel[m.colName] = '00:00:00'
break
case 116: // 選擇時間
formModel[m.colName] = '00:00'
break
case 120: // 數字
case 121:
formModel[m.colName] = 0
break
case 150: // 勾選
case 151: // 開關
formModel[m.colName] = false
break
case 153: // 單選組
case 160: // 下拉單選
case 162: // 下拉聯(lián)動
formModel[m.colName] = null
break
case 152: // 多選組
case 161: // 下拉多選
formModel[m.colName] = []
break
}
// 看看有沒有設置默認值
if (typeof m.defaultValue !== 'undefined') {
switch (m.defaultValue) {
case '':
break
case '{}':
formModel[m.colName] = {}
break
case '[]':
formModel[m.colName] = []
break
case 'date':
formModel[m.colName] = new Date()
break
default:
formModel[m.colName] = m.defaultValue
break
}
}
}
// 同步父組件的v-model
context.emit('update:modelValue', formModel)
}
可以根據類型和默認值念搬,設置model的屬性抑堡,這樣就方便多了。
多列的表單
這個是最復雜的朗徊,分為兩種情況:單列的擠一擠首妖、多列的搶位置。
單列
單列的表單有一個特點爷恳,一行比較寬松有缆,那么有時候就需要兩個組件在一行里顯示,其他的還是一行一個組件,那么要如何調整呢棚壁?
這里做一個設定:
- 一個組件一行的杯矩,記做1
- 兩個組件擠一行的,記做-2
- 三個組件擠一行的袖外,記做-3
以此類推史隆,理論上最多支持-24,當然實際上似乎沒有這么寬的顯示器曼验。
這樣記錄之后泌射,我們就可以判斷,≥1的記做span=24鬓照,負數的熔酷,用24去除,得到的就是span的數字颖杏。當然記得取整數纯陨。
為啥用負數做標記呢?就是為了區(qū)分開多列的調整留储。
多列
多列的表單有一個特點,一個格子比較小咙轩,有些組件太長放不下获讳,這個時候這個組件就要搶后面的格子來用。
那么我們還是做一個設定:
- 一個組件占一格的活喊,還是記做1
- 一個組件占兩格的丐膝,記做2
- 一個組件占三格的,記做3
以此類推钾菊。
這樣記錄之后帅矗,我們可以判斷,≤1的煞烫,記做 24 / 列數浑此,大于1的記做 24/ 列數 * n。
這樣就可以了滞详,可以兼容單列的設置凛俱,不用因為單列變多列而調整設置。
只是有個小麻煩料饥,占得格子太多的話蒲犬,就會提取擠到下一行,而本行會出現“空缺”岸啡。
這個暫時靠人工調整吧原叮。
畢竟哪個字段在前面,還是需要人工設置的。
一頓分析猛如虎奋隶,一看代碼沒幾行擂送。
// 調整行列
const span = reactive({})
// 根據配置里面的colCount,設置span
const getSpan = () => {
const formColCount = formMeta.formColCount // 列數
const moreColSpan = 24 / formColCount // 一個格子占多少份
if (formColCount === 1) {
// 一列的情況
for (const key in formItemMeta) {
const m = formItemMeta[key]
if (typeof m.colCount === 'undefined') {
span[m.controlId] = moreColSpan
} else {
if (m.colCount >= 1) {
// 單列达布,多占的也只有24格
span[m.controlId] = moreColSpan
} else if (m.colCount < 0) {
// 擠一擠的情況团甲, 24 除以 占的份數
span[m.controlId] = moreColSpan / (0 - m.colCount)
}
}
}
} else {
// 多列的情況
for (const key in formItemMeta) {
const m = formItemMeta[key]
if (typeof m.colCount === 'undefined') {
span[m.controlId] = moreColSpan
} else {
if (m.colCount < 0 || m.colCount === 1) {
// 多列,擠一擠的占一份
span[m.controlId] = moreColSpan
} else if (m.colCount > 1) {
// 多列黍聂,占的格子數 * 份數
span[m.controlId] = moreColSpan * m.colCount
}
}
}
}
}
最后看看效果躺苦,可以動態(tài)設置列數:
如果空間夠的話,最多可以是24列产还。應該是夠用了匹厘。