form-generator
form-generator copied to clipboard
表单解析器 · 开发教程
本文描述的解析器,是一个能将form-generator导出的json表单,解析为一个真实表单的程序。 接下来的行文中使用【json表单】表示form-generator导出的json表单。
剧透:本文其实就是带大家阅读parser.vue源码,哈哈。
布局
json表单目前支持两种布局: colFormItem和rowFormItem
1.1 colFormItem布局
colFormItem布局(以el-input为例)对应的json形式如下:
{
"__config__": {
"label": "单行文本",
"labelWidth": null,
"showLabel": true,
"changeTag": true,
"tag": "el-input",
"tagIcon": "input",
"required": true,
"layout": "colFormItem",
"span": 12,
"document": "https://element.eleme.cn/#/zh-CN/component/input",
"regList": [{
"pattern": "/^1(3|4|5|7|8|9)\\d{9}$/",
"message": "手机号格式错误"
}]
},
"__slot__": {
"prepend": "",
"append": ""
},
"__vModel__": "mobile",
"placeholder": "请输入手机号",
"style": {
"width": "100%"
},
"clearable": true,
"prefix-icon": "el-icon-mobile",
"suffix-icon": "",
"maxlength": 11,
"show-word-limit": true,
"readonly": false,
"disabled": false
}
colFormItem布局对应的目标实际代码如下 :
<el-col :span="12">
<el-form-item label="单行文本" prop="mobile">
<el-input v-model="formData.mobile" placeholder="请输入手机号" :maxlength="11" show-word-limit clearable
prefix-icon='el-icon-mobile' :style="{width: '100%'}"></el-input>
</el-form-item>
</el-col>
在这个json到xml的解析过程中,form-generator的parser使用jsx来完成
...
const layouts = {
colFormItem(h, scheme) {
const config = scheme.__config__
const listeners = buildListeners.call(this, scheme)
let labelWidth = config.labelWidth ? `${config.labelWidth}px` : null
if (config.showLabel === false) labelWidth = '0'
return (
<el-col span={config.span}>
<el-form-item label-width={labelWidth} prop={scheme.__vModel__}
label={config.showLabel ? config.label : ''}>
<render conf={scheme} {...{ on: listeners }} />
</el-form-item>
</el-col>
)
},
...
}
1.2 rowFormItem布局
rowFormItem布局对应的json形式如下:
{
"__config__": {
"layout": "rowFormItem",
"tagIcon": "row",
"layoutTree": true,
"document": "https://element.eleme.cn/#/zh-CN/component/layout#row-attributes",
"span": 12,
"formId": 104,
"renderKey": 1594570310282,
"componentName": "row104",
"children": []
},
"type": "default",
"justify": "start",
"align": "top"
}
对应的目标代码如下:
<el-col :span="12">
<el-row>
</el-row>
</el-col>
同样使用jsx来完成布局解析:
rowFormItem(h, scheme) {
let child = renderChildren.apply(this, arguments)
if (scheme.type === 'flex') {
child = <el-row type={scheme.type} justify={scheme.justify} align={scheme.align}>
{child}
</el-row>
}
return (
<el-col span={scheme.span}>
<el-row gutter={scheme.gutter}>
{child}
</el-row>
</el-col>
)
}
值得注意的是,json表单支持嵌套; 通过__config__.children记录嵌套关系。使用renderChildren递归解析。(目前仅对rowFormItem布局的children做解析)
function renderChildren(h, scheme) {
const config = scheme.__config__
if (!Array.isArray(config.children)) return null
return renderFormItem.call(this, h, config.children)
}
完整的代码,请阅读parse源码,此链接中的版本并不算复杂。
数据和逻辑
传统的vue格式表单,我们可能需要写如下格式的js,完成element UI表单的数据和逻辑。
export default {
data() {
return {
formData: {
mobile: undefined,
field103: undefined,
},
rules: {
mobile: [{
required: true,
message: '请输入手机号',
trigger: 'blur'
}, {
pattern: /^1(3|4|5|7|8|9)\d{9}$/,
message: '手机号格式错误',
trigger: 'blur'
}],
field103: [{
required: true,
message: '请输入密码',
trigger: 'blur'
}],
},
}
},
methods: {
submitForm() {
this.$refs['elForm'].validate(valid => {
if (!valid) return
// TODO 提交表单
})
},
resetForm() {
this.$refs['elForm'].resetFields()
},
}
}
对于解析器来说,这是一个抽象的过程:
- 数据部分: 构建表单数据实现如下:
data() {
const data = {
formConfCopy: deepClone(this.formConf),
[this.formConf.formModel]: {},
[this.formConf.formRules]: {}
}
this.initFormData(data.formConfCopy.fields, data[this.formConf.formModel])
this.buildRules(data.formConfCopy.fields, data[this.formConf.formRules])
return data
},
- 逻辑部分: 请阅读,源码 methods 部分。这块和你日常vue编程差不多,只不过属性都是抽象的。
JSON表单结构说明
上边的一系列操作,都是建立在理解json表单都有哪些内容的基础上的。详细请参阅JSON参数对照表
form-generator中的render.js
render.js就是对vue的render函数的简单定制封装。如果你还不理解vue的render函数,请移步至:渲染函数 & JSX
render.js实现的功能是将json表单中的__config__.tag解析为具体的vue组件; 其工作过程可以理解为以下3个部分:
render(h) {
const dataObject = makeDataObject()
const confClone = deepClone(this.conf)
const children = []
// 1 如果slots文件夹存在与当前tag同名的文件,则执行文件中的代码
mountSlotFlies.call(this, h, confClone, children)
// 2 将字符串类型的事件,发送为消息
emitEvents.call(this, confClone)
// 3 将json表单配置转化为vue render可以识别的 “数据对象(dataObject)”
buildDataObject.call(this, confClone, dataObject)
return h(this.conf.__config__.tag, dataObject, children)
}
更多细节:源码render/render.js
关于拓展和讨论
本项目仅仅是开了个表单渲染头;实际要根据需求的差异,要做不一样的定制。之所以在issue写文章,是希望各位能充分利用好下边的评论功能,大家友好探讨。
系列教程: 《表单设计器 · 开发教程》 《表单解析器 · 开发教程》 《vue代码生成器 · 开发教程》 《vue代码预览器 · 开发教程》
怎么没有看到表单解析器的开发教程呢
同问呢
说好的表单解析开发教程呢, 大佬是不是忘记弄了
怎么没有看到表单解析器的开发教程呢
parser啊大哥 大佬开始就写了 这是parser的解说 看下router路由 可以直接用的 扩展的话稍微看下你就懂了不用人家说 并且 编辑的时候运行有单独的iframe引入 已经和这功能解耦了
我在parser上通过异步下载json 回来进行解析成页面,所有的表单项都能出来,唯独是表单的校验功能不正常,有大佬能正常校验的吗
请问如果设计一个标签组件,内容是一个行容器,可行吗?想了挺久,没想到合适的解决方案,恳请各位大佬指点一下
动态数据,除了在formConf 内直接构造外(即在formConf数据未到 parser 解析渲染前),还有其它方式可以动态构造吗
我在parser上通过异步下载json 回来进行解析成页面,所有的表单项都能出来,唯独是表单的校验功能不正常,有大佬能正常校验的吗
请问你的表单校验问题解决了吗?
我在parser上通过异步下载json 回来进行解析成页面,所有的表单项都能出来,唯独是表单的校验功能不正常,有大佬能正常校验的吗
请问你的表单校验问题解决了吗?
同问,为什么我的表单本地数据可以服务端异步传来的解析不成功?
我在parser上通过异步下载json 回来进行解析成页面,所有的表单项都能出来,唯独是表单的校验功能不正常,有大佬能正常校验的吗
请问你的表单校验问题解决了吗?
同问,为什么我的表单本地数据可以服务端异步传来的解析不成功?
表单校验的初始化应该是在获取到数据后,可以watch数据,拿到后再构建表单校验规则
这是来自QQ邮箱的自动回复邮件。您发送的邮件已收到,任瀚
我在parser上通过异步下载json 回来进行解析成页面,所有的表单项都能出来,唯独是表单的校验功能不正常,有大佬能正常校验的吗
怎么异步解析数据呢?望指教
这是来自QQ邮箱的自动回复邮件。您发送的邮件已收到,任瀚
请问 解析时候 我加了一个题目逻辑的设置,把不需要的题目隐藏,用display:none; 然后radio的选种样式就没有了,这个有遇到吗 怎么处理
这是来自QQ邮箱的自动回复邮件。您发送的邮件已收到,任瀚
大侠们,自定义组件应该在哪里获取__config__的数据
这是来自QQ邮箱的自动回复邮件。您发送的邮件已收到,任瀚