业精于勤荒于嬉 行成于思毁于随
持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第1天,点击查看活动详情
经历了九月的休整,又迎来金秋十月更文挑战,前端技术浩繁如海,我也仅仅是初学者一家之言,如有异同,欢迎臧否
来由
我司业务面向的是大量的B端客户,B端客户的业务特点是什么呢?表单字段多,样式要求低,重业务实现,轻页面交互 不同的客户特别是跨行业的客户之间,字段差异极大,但是表单类型相对统一,经过业务沉淀,所以决定采用JSON的形式来组织业务表单的实现。
抽象
要想实现JSON化的表单,首先需要的就是总结提炼共性的属性及方法,经过整理归纳如下:
- 字段名
field及字段描述fieldLabel要支持自定义【1】 - 表单类型: 文本、文本域、数字、日期、日期时间、下拉选择【2】
- 表单项的联动处理【3】
- 表单项所占据宽度(24栅格布局)【4】
实现 以elementUI为例
- 最简单的当然就是【1】了,本身elementUI的表单就自带
prop与label属性
<el-form-item
:prop="item.uniqFieldName"
:label="item.fieldCustomTitle"
>
...
</el-form-item>
- 差不多难度的当然是【4】通过elementUI提供的
row与col组件即可实现一行两个,一行三个,独占一行,一行四个等各种布局。
<el-row :gutter="20">
<el-col :span="8"><div class="grid-content bg-purple"></div></el-col>
<el-col :span="8"><div class="grid-content bg-purple"></div></el-col>
<el-col :span="4"><div class="grid-content bg-purple"></div></el-col>
<el-col :span="4"><div class="grid-content bg-purple"></div></el-col>
</el-row>
- 表单类型处理,表单类型这里有两种实现,一种是类
JSX的语法,通过h函数来实现,一种是通过v-if指令来实现,我个人倾向于v-if指令,主要原因有三点: -
h函数相比较JSX语法,还是具有局限性
-
h函数相比较v-if指令,可读性更差
-
h函数相比较v-if指令,后期可维护性和扩展性差
综上,我这里采用的是v-if指令的实现方式,组件的属性会设计在以JSON格式交互的模版里
<el-input
v-if="item.searchType === 'text'"
v-model="searchForm[item.uniqFieldName]"
:placeholder="item.placeholder"
/>
<el-date-picker
v-else-if="item.searchType === 'datetime'"
v-model="searchForm[item.uniqFieldName]"
:type="judgeIsDouble(item)"
value-format="yyyy-MM-dd HH:mm:ss"
start-placeholder="开始日期"
end-placeholder="结束日期"
:default-time="['00:00:00','23:59:59']"
align="right"
/>
....
- 最难的【3】了,表单项的联动处理,这里同样有两个思路:
-
- 通过
watch方法去监听form这个model的变化,然后遍历模版配置实现值联动
- 通过
-
- 通过注册
change事件,分别处理每个表单项上所关联的值联动。
- 通过注册
这两个方案,看起来方案1会执行更多的无效代码,方案2精准触发,能准确命中要处理的表单项,而实际上,我们的需求可能是这样的: 总价= 单价 x 数量 单价 = 总价 / 数量 数量 = 总价 / 单价 ,这里有可能需要锁定单价或锁定数量。所以,我们需要将方案1和方案2进行结合来使用。
watch: {
form () {
model.map(k => {
if (k.computedFunc) {
this.deal(k.computedFunc)
}
})
},
...
methods: {
onChange (e, item) {
this.deal(item.computedFunc)
}
}
总结
通过模版解析的方式,我们可以将一些通用的表单界面进行封装,并统一处理相同的无关业务逻辑的一些功能,避免每次处理新业务时需要重复编写非业务代码,将关注点更多的聚焦到业务上来,为我们的业务赋能提效。