GenerateForm
表单生成器组件,通过 JSON Schema
快速渲染出表单页面。
代码演示
基础用法
直接根据 JSON Schema
渲染出表单,获取表单数据。
查看代码
vue
<template>
<fm-generate-form
:data="jsonData"
ref="generateForm"
></fm-generate-form>
<el-button @click="handleSubmit">Submit</el-button>
</template>
<script setup>
import { ref } from 'vue'
import { ElMessageBox } from 'element-plus'
const generateForm = ref()
const jsonData = {"list":[{"type":"input","icon":"icon-input","options":{"width":"","defaultValue":"","required":false,"requiredMessage":"","dataType":"","dataTypeCheck":false,"dataTypeMessage":"","pattern":"","patternCheck":false,"patternMessage":"","validatorCheck":false,"validator":"","placeholder":"","customClass":"","disabled":false,"labelWidth":100,"isLabelWidth":false,"hidden":false,"dataBind":true,"showPassword":false,"remoteFunc":"func_z2lqyv1a","remoteOption":"option_z2lqyv1a"},"events":{"onChange":"","onFocus":"","onBlur":""},"name":"单行文本","key":"z2lqyv1a","model":"input_z2lqyv1a","rules":[]},{"type":"textarea","icon":"icon-diy-com-textarea","options":{"width":"","defaultValue":"","required":false,"requiredMessage":"","disabled":false,"pattern":"","patternMessage":"","validatorCheck":false,"validator":"","placeholder":"","customClass":"","labelWidth":100,"isLabelWidth":false,"hidden":false,"dataBind":true,"remoteFunc":"func_geb5vsy8","remoteOption":"option_geb5vsy8"},"events":{"onChange":"","onFocus":"","onBlur":""},"name":"多行文本","key":"geb5vsy8","model":"textarea_geb5vsy8","rules":[]},{"type":"radio","icon":"icon-radio-active","options":{"inline":false,"defaultValue":"","showLabel":false,"options":[{"value":"Option 1","label":"Option 1"},{"value":"Option 2","label":"Option 2"},{"value":"Option 3","label":"Option 3"}],"required":false,"requiredMessage":"","validatorCheck":false,"validator":"","width":"","remote":false,"remoteType":"datasource","remoteOption":"option_jg58x37w","remoteOptions":[],"props":{"value":"value","label":"label"},"remoteFunc":"func_jg58x37w","customClass":"","labelWidth":100,"isLabelWidth":false,"hidden":false,"dataBind":true,"disabled":false},"events":{"onChange":""},"name":"单选框组","key":"jg58x37w","model":"radio_jg58x37w","rules":[]}],"config":{"labelWidth":100,"labelPosition":"right","size":"default","customClass":"","ui":"element","layout":"horizontal","labelCol":3,"width":"100%","hideLabel":false,"hideErrorMessage":false,"eventScript":[{"key":"mounted","name":"mounted","func":""}],"dataSource":[]}}
const handleSubmit = () => {
generateForm.value.getData().then(data => {
ElMessageBox.alert(data, '表单数据')
})
}
</script>
TIP
getData
是异步方法,默认情况获取数据前验证表单数据,只有验证成功才能获取到表单数据 data ;若不需要表单验证,想要直接获取表单数据,可以添加参数 getData(false)
将不会验证表单数据
加载表单数据
查看代码
vue
<template>
<fm-generate-form
:data="jsonData"
:value="editData"
ref="generateForm"
></fm-generate-form>
<el-button @click="handleSubmit" type="primary">提交数据</el-button>
<el-button @click="handleSetData">设置新数据</el-button>
<el-button @click="handleReset" >重置表单</el-button>
</template>
<script setup>
import { ref } from 'vue'
import { ElMessageBox } from 'element-plus'
const generateForm = ref()
const jsonData = {"list":[{"type":"input","icon":"icon-input","options":{"width":"","defaultValue":"","required":false,"requiredMessage":"","dataType":"","dataTypeCheck":false,"dataTypeMessage":"","pattern":"","patternCheck":false,"patternMessage":"","validatorCheck":false,"validator":"","placeholder":"","customClass":"","disabled":false,"labelWidth":100,"isLabelWidth":false,"hidden":false,"dataBind":true,"showPassword":false,"remoteFunc":"func_z2lqyv1a","remoteOption":"option_z2lqyv1a"},"events":{"onChange":"","onFocus":"","onBlur":""},"name":"单行文本","key":"z2lqyv1a","model":"input","rules":[]},{"type":"textarea","icon":"icon-diy-com-textarea","options":{"width":"","defaultValue":"","required":false,"requiredMessage":"","disabled":false,"pattern":"","patternMessage":"","validatorCheck":false,"validator":"","placeholder":"","customClass":"","labelWidth":100,"isLabelWidth":false,"hidden":false,"dataBind":true,"remoteFunc":"func_geb5vsy8","remoteOption":"option_geb5vsy8"},"events":{"onChange":"","onFocus":"","onBlur":""},"name":"多行文本","key":"geb5vsy8","model":"text","rules":[]},{"type":"radio","icon":"icon-radio-active","options":{"inline":false,"defaultValue":"","showLabel":false,"options":[{"value":"Option 1","label":"Option 1"},{"value":"Option 2","label":"Option 2"},{"value":"Option 3","label":"Option 3"}],"required":false,"requiredMessage":"","validatorCheck":false,"validator":"","width":"","remote":false,"remoteType":"datasource","remoteOption":"option_jg58x37w","remoteOptions":[],"props":{"value":"value","label":"label"},"remoteFunc":"func_jg58x37w","customClass":"","labelWidth":100,"isLabelWidth":false,"hidden":false,"dataBind":true,"disabled":false},"events":{"onChange":""},"name":"单选框组","key":"jg58x37w","model":"radio","rules":[]}],"config":{"labelWidth":100,"labelPosition":"right","size":"default","customClass":"","ui":"element","layout":"horizontal","labelCol":3,"width":"100%","hideLabel":false,"hideErrorMessage":false,"eventScript":[{"key":"mounted","name":"mounted","func":""}],"dataSource":[]}}
const editData = {
input: 'input',
text: 'text',
radio: 'Option 1'
}
const handleSubmit = () => {
generateForm.value.getData().then(data => {
ElMessageBox.alert(data, '表单数据')
})
}
const handleReset = () => {
generateForm.value.reset()
}
const handleSetData = () => {
generateForm.value.setData({
input: 'new input',
text: 'new text',
radio: 'Option 3'
})
}
</script>
TIP
:value
属性给表单赋值,只有在表单初始化时才能生效,表单和默认数据一起加载,重置表单不会清空默认数据。
setData
可以在表单初始化后动态赋值,重置表单将会清空表单数据。
异步加载表单
查看代码
vue
<template>
<fm-generate-form
:data="jsonData"
ref="generateForm"
></fm-generate-form>
<el-button @click="handleLoad" >加载表单</el-button>
</template>
<script setup>
import { ref, nextTick } from 'vue'
const generateForm = ref()
const jsonData = ref({})
const handleLoad = () => {
// 直接将json赋值给data属性
jsonData.value = {"list":[{"type":"grid","icon":"icon-RectangleCopy","columns":[{"type":"col","options":{"span":12,"offset":0,"push":0,"pull":0,"xs":24,"sm":12,"md":12,"lg":12,"xl":12,"customClass":""},"list":[{"type":"select","icon":"icon-select","options":{"defaultValue":"","multiple":false,"disabled":false,"clearable":false,"placeholder":"","required":false,"requiredMessage":"","validatorCheck":false,"validator":"","showLabel":false,"width":"","options":[{"value":"1111"},{"value":"2222"},{"value":"3333"}],"remote":true,"remoteType":"datasource","remoteOption":"option_6lqq9bu5","filterable":false,"remoteOptions":[],"props":{"value":"value","label":"label"},"remoteFunc":"func_6lqq9bu5","customClass":"","labelWidth":100,"isLabelWidth":false,"hidden":false,"dataBind":true,"tableColumn":false,"remoteDataSource":"getoptions"},"events":{"onChange":"","onFocus":"","onBlur":""},"name":"下拉选择框","novalid":{},"key":"6lqq9bu5","model":"select_6lqq9bu5","rules":[]}],"key":"nhfkr3bc"}],"options":{"gutter":0,"justify":"start","align":"top","customClass":"","hidden":false,"flex":true,"responsive":true,"remoteFunc":"func_ugqp2jf3","remoteOption":"option_ugqp2jf3"},"name":"栅格布局","key":"ugqp2jf3","model":"grid_ugqp2jf3","rules":[]}],"config":{"labelWidth":100,"labelPosition":"right","size":"default","customClass":"","ui":"element","layout":"horizontal","labelCol":3,"width":"100%","hideLabel":false,"hideErrorMessage":false,"eventScript":[{"key":"mounted","name":"mounted","func":""}],"dataSource":[]}}
// 在 nextTick 下再调用表单的 refresh ,这是必须的,保证表单重新加载数据
nextTick(() => {
generateForm.value.refresh()
})
}
</script>
监听表单数据变化
字段: --- 更改的后的值:
查看代码
vue
<template>
<fm-generate-form
:data="jsonData"
ref="generateForm"
@on-change="onChange"
></fm-generate-form>
<div>字段:{{changeData.field}} --- 更改的后的值:{{changeData.value}}</div>
</template>
<script setup>
import { ref, reactive } from 'vue'
const jsonData = {"list":[{"type":"input","icon":"icon-input","options":{"width":"","defaultValue":"","required":false,"requiredMessage":"","dataType":"","dataTypeCheck":false,"dataTypeMessage":"","pattern":"","patternCheck":false,"patternMessage":"","validatorCheck":false,"validator":"","placeholder":"","customClass":"","disabled":false,"labelWidth":100,"isLabelWidth":false,"hidden":false,"dataBind":true,"showPassword":false,"remoteFunc":"func_wwyplsj9","remoteOption":"option_wwyplsj9","tableColumn":false},"events":{"onChange":"","onFocus":"","onBlur":""},"name":"单行文本","key":"wwyplsj9","model":"input","rules":[]},{"type":"textarea","icon":"icon-diy-com-textarea","options":{"width":"","defaultValue":"","required":false,"requiredMessage":"","disabled":false,"pattern":"","patternMessage":"","validatorCheck":false,"validator":"","placeholder":"","customClass":"","labelWidth":100,"isLabelWidth":false,"hidden":false,"dataBind":true,"remoteFunc":"func_2ay04pyh","remoteOption":"option_2ay04pyh","tableColumn":false},"events":{"onChange":"","onFocus":"","onBlur":""},"name":"多行文本","key":"2ay04pyh","model":"text","rules":[]}],"config":{"labelWidth":100,"labelPosition":"right","size":"default","customClass":"","ui":"element","layout":"horizontal","labelCol":3,"width":"100%","hideLabel":false,"hideErrorMessage":false,"eventScript":[{"key":"mounted","name":"mounted","func":""}],"dataSource":[]}}
const generateForm = ref()
const changeData = reactive({
field: '',
value: ''
})
const onChange = (field, value) => {
changeData.field = field
changeData.value = value
}
</script>
动态设置表单禁用隐藏
查看代码
vue
<template>
<fm-generate-form
:data="jsonData"
ref="generateForm"
></fm-generate-form>
<el-button type="primary" @click="handleHide">隐藏文本框</el-button>
<el-button type="primary" @click="handleDisplay">显示文本框</el-button>
<el-button type="primary" @click="handleDisabled">禁用文本框</el-button>
<el-button type="primary" @click="handleEnabled">启用文本框</el-button>
</template>
<script setup>
import { ref, reactive } from 'vue'
const generateForm = ref()
const jsonData = reactive({"list":[{"type":"input","icon":"icon-input","options":{"width":"","defaultValue":"","required":false,"requiredMessage":"","dataType":"","dataTypeCheck":false,"dataTypeMessage":"","pattern":"","patternCheck":false,"patternMessage":"","validatorCheck":false,"validator":"","placeholder":"","customClass":"","disabled":false,"labelWidth":100,"isLabelWidth":false,"hidden":false,"dataBind":true,"showPassword":false,"remoteFunc":"func_wwyplsj9","remoteOption":"option_wwyplsj9","tableColumn":false},"events":{"onChange":"","onFocus":"","onBlur":""},"name":"单行文本","key":"wwyplsj9","model":"input","rules":[]},{"type":"textarea","icon":"icon-diy-com-textarea","options":{"width":"","defaultValue":"","required":false,"requiredMessage":"","disabled":false,"pattern":"","patternMessage":"","validatorCheck":false,"validator":"","placeholder":"","customClass":"","labelWidth":100,"isLabelWidth":false,"hidden":false,"dataBind":true,"remoteFunc":"func_2ay04pyh","remoteOption":"option_2ay04pyh","tableColumn":false},"events":{"onChange":"","onFocus":"","onBlur":""},"name":"多行文本","key":"2ay04pyh","model":"text","rules":[]},{"type":"radio","icon":"icon-radio-active","options":{"inline":false,"defaultValue":"","showLabel":false,"options":[{"value":"Option 1","label":"Option 1"},{"value":"Option 2","label":"Option 2"},{"value":"Option 3","label":"Option 3"}],"required":false,"requiredMessage":"","validatorCheck":false,"validator":"","width":"","remote":false,"remoteType":"datasource","remoteOption":"option_3esmng86","remoteOptions":[],"props":{"value":"value","label":"label"},"remoteFunc":"func_3esmng86","customClass":"","labelWidth":100,"isLabelWidth":false,"hidden":false,"dataBind":true,"disabled":false,"tableColumn":false},"events":{"onChange":""},"name":"单选框组","key":"3esmng86","model":"radio","rules":[]}],"config":{"labelWidth":100,"labelPosition":"right","size":"default","customClass":"","ui":"element","layout":"horizontal","labelCol":3,"width":"100%","hideLabel":false,"hideErrorMessage":false,"eventScript":[{"key":"mounted","name":"mounted","func":""}],"dataSource":[]}})
// input, text 为字段属性中配置的字段标识
const handleHide = () => {
generateForm.value.hide(['input', 'text'])
}
const handleDisplay = () => {
generateForm.value.display(['input', 'text'])
}
const handleDisabled = () => {
generateForm.value.disabled(['input', 'text'], true)
}
const handleEnabled = () => {
generateForm.value.disabled(['input', 'text'], false)
}
</script>
TIP
禁用和启用操作因为是修改表单 json 设置的,所以需要保证 jsonData 为响应式数据,这里用到了 reactive
获取表单字段组件实例
可以通过【字段标识】来获取组件的实例,来对表单的字段组件做一些操作。
js
// 获取文本框实例,执行 focus 方法。
getComponent('input').focus()
// 调用子表单实例隐藏一整列
getComponent('table').hide(['input'])
// 获取子表单中第一行的 input 组件
getComponent('table.0.input')
TIP
如果表单中有多个相同的字段标识,getComponent 返回的是数组,包含所有的实例。
自定义样式动态添加
查看代码
vue
<template>
<fm-generate-form
:data="jsonData"
ref="generateForm"
></fm-generate-form>
<el-button @click="handleAdd">添加样式</el-button>
<el-button @click="handleRemove">移除样式</el-button>
</template>
<script setup>
import { ref, nextTick, onMounted } from 'vue'
const generateForm = ref()
const jsonData = ref({})
onMounted(() => {
jsonData.value = {"list":[{"type":"input","icon":"icon-input","options":{"width":"","defaultValue":"","required":false,"requiredMessage":"","dataType":"","dataTypeCheck":false,"dataTypeMessage":"","pattern":"","patternCheck":false,"patternMessage":"","validatorCheck":false,"validator":"","placeholder":"","customClass":"","disabled":false,"labelWidth":100,"isLabelWidth":false,"hidden":false,"dataBind":true,"showPassword":false,"remoteFunc":"func_syyx0jhb","remoteOption":"option_syyx0jhb"},"events":{"onChange":"","onFocus":"","onBlur":""},"name":"Input","key":"syyx0jhb","model":"input","rules":[]},{"type":"textarea","icon":"icon-diy-com-textarea","options":{"width":"","defaultValue":"","required":false,"requiredMessage":"","disabled":false,"pattern":"","patternMessage":"","validatorCheck":false,"validator":"","placeholder":"","customClass":"","labelWidth":100,"isLabelWidth":false,"hidden":false,"dataBind":true,"remoteFunc":"func_jxgb18ns","remoteOption":"option_jxgb18ns"},"events":{"onChange":"","onFocus":"","onBlur":""},"name":"Textarea","key":"jxgb18ns","model":"text","rules":[]},{"type":"radio","icon":"icon-radio-active","options":{"inline":false,"defaultValue":"","showLabel":false,"options":[{"value":"Option 1","label":"Option 1"},{"value":"Option 2","label":"Option 2"},{"value":"Option 3","label":"Option 3"}],"required":false,"requiredMessage":"","validatorCheck":false,"validator":"","width":"","remote":false,"remoteType":"datasource","remoteOption":"option_o6xn3cpa","remoteOptions":[],"props":{"value":"value","label":"label"},"remoteFunc":"func_o6xn3cpa","customClass":"","labelWidth":100,"isLabelWidth":false,"hidden":false,"dataBind":true,"disabled":false},"events":{"onChange":""},"name":"Radio","key":"o6xn3cpa","model":"radio","rules":[]}],"config":{"labelWidth":100,"labelPosition":"right","size":"default","customClass":"","ui":"element","layout":"horizontal","labelCol":3,"width":"100%","hideLabel":false,"hideErrorMessage":false,"eventScript":[{"key":"mounted","name":"mounted","func":""}],"dataSource":[]}}
nextTick(() => {
generateForm.value.refresh()
})
})
const handleAdd = () => {
generateForm.value.addClassName(['input', 'text'], 'custom-style')
}
const handleRemove = () => {
generateForm.value.removeClassName(['input', 'text'], 'custom-style')
}
</script>
<style>
.custom-style{
padding: 10px;
}
.custom-style .el-form-item__label{
font-size: 16px;
color: red;
}
</style>
API
属性
参数 | 说明 | 类型 | 默认值 |
---|---|---|---|
data | 表单 JSON 配置数据 | object | {} |
value | 表单数据 | object | - |
remote | 表单配置的远端方法 | object | {} |
edit | 表单可编辑状态 | boolean | true |
remote-option | 表单动态选项配置 | object | {} |
print-read | 打印阅读模式,表单值文本展示 | boolean | false |
事件
事件名 | 说明 | 回调参数 |
---|---|---|
on-change | 表单项数据变化时触发 | (field, value, data) field: 数据改变的字段标识 value: 数据改变后的值 |
方法
方法名 | 说明 | 参数 |
---|---|---|
getData | 获取表单绑定的数据 | (isValidate = true) => promise 传入 false 不进行表单校验 |
reset | 重置表单数据 | () => void |
setData | 设置表单数据 | ({id: value}) => void |
hide | 隐藏表单字段 | (fields: []) => void |
display | 显示表单隐藏的字段 | (fields: []) => void |
disabled | 动态设置表单字段是否禁用 | (fields: [], disabled: true | false) => void |
refresh | 刷新表单,当表单 JSON 改变时,需调用该方法重新加载表单 | () => void |
getValue | 获取某一字段输入值 | (field) => value |
getValues | 获取表单所有字段的值 | () => object |
sendRequest | 执行数据源请求 | (name: 数据源名称, args: 数据源参数) => promise |
getComponent | 获取表单中字段组件实例 | (field: 字段名称) => object | array |
addClassName | 表单项添加样式类 | (fields: [], className) |
removeClassName | 移除表单样式类 | (fields: [], className) |
setRules | 设置表单字段验证规则 | (field, rules) |
setOptions | 设置表单字段配置项,参见 字段可配置项 | (fields, options) |
setOptionData | 动态选项数据赋值,需要 options.remote 为 true 时生效 | (fields, newData) |
refreshFieldDataSource | 刷新字段绑定的数据源数据 | (field, args: 数据源参数) |
getFieldDataSource^3.5.4 | 获取字段绑定的数据源数据值 | (field) |
validate | 验证表单字段 | (fields: []) => promise |
triggerEvent | 调用表单配置的js事件 | (eventName: 事件名称, args: 事件参数) |