巨大的表单,在复杂的管理后台中最为常见。
什么叫大表单呢?
1、字段多
2、结构复杂
3、各种交互
就相当于网页上的银行单吧,并且有各类交互(增删改查)、校验。
由于近期做的这类表单较多,作此篇,权当总结与分享。
我相信此时的你使用的前端框架也是基于mvvm思想的框架(如vue、react等)。
所以,还得先简短发表一下我对mvvm的理解。
首先,mvvm的推崇不是毫无逻辑的,用的人多,自然说明用的舒服。
拆解:m(model)、v(view)、vm(viewModel)。
m与v是死的,vm是活的。vm就是核心,中枢神经。
由于框架的处理,vm的变动会直接体现在m与v中。
也就是说,页面交互逻辑、页面数据其实是通过控制vm来实现的。
(react的state、props,vue中的model、props都可以成为vm角色)
因此,我对大表单的设计会围绕着vm来进行。
对于大部分情况,我们会将vm直接定义成一个对象,将所有的字段都写进去。
编写view部分,也就是切图部分。每一个模块切一片,将vm里的字段对应的写进去。
但是我更倾向于页面可配置化的写法。
将页面中所有的字段定义为一个config对象,这个config对象包含了字段所有的信息(理想状态)。
{
key: 'chineseName',
value: null,
label: '公司名称(中文)',
type: 'input',
config: {
isRequested: true,
validReg: /^[\u4e00-\u9fa5\s]+$/,
validMsg: '请输入纯中文!'
}
},
{
key: 'companyType',
value: 1,
label: '公司类型',
type: 'select',
config: {
isRequested: true,
options: companyTypeArray()
}
}
比如是input
还是select
,或者checkbox
,单选
或者多选
等等。
以及字段的label
,校验规则
等。
基于这个config
,可以编写函数提取出我们需要的vm
对象。
// 获取数据模型
getModuleObj: arr => {
return arr.reduce((obj, item) => {
obj[item.key] = item.value
return obj
}, {})
}
我觉得比较重要的是,我从一个config
中,就能看出整个页面的逻辑与数据。
当需要修改、新增、删除时,只需要操作config
就行了。
这是第一步,确定好config
的思路后,进入我认为大表单最重要的部分。
与接口数据的交互。
vm是我们页面展示的数据,传给api的,是另一个数据。
两者在层级结构上是类似的。
这里不应该有太大差异。如果差异太大,说明一开始字段定义的时候前端并没有参与。
fn1(vmData) -> apiData
比如这里我需要将数组转换为|分隔的字符串
// 递归处理modelData数据 modelData => apiData
const setParam = data => {
if (data instanceof Array) {
if (data.length > 0) {
if (data[0] instanceof Object) {
for (let i = 0; i < data.length; i++) {
data[i] = setParam(data[i])
}
} else {
data = '|' + data.join('|') + '|'
return data
}
} else {
data = '||'
}
} else if (data instanceof Object) {
for (let k in data) {
data[k] = setParam(data[k])
}
}
return data
}
fn2(apiData) -> vmData
只需要编写两个函数做数据的转换即可,层级较深可用递归处理。
总结一下,我这里对大表单的处理,其实就两点。
1、config描述文件(vm、view以此配置)
2、vm、apiData的相互转换(数据录入与数据回显)
能妥善处理好这两个问题,基本上大表单也就处理好了,剩下的就是细节的打磨。