vue3-form-designer
v3.0.1
Published
基于vue3和element-plus的表单设计器,支持自定义组件
Downloads
2
Readme
element-plus-form-designer
基于 vue3 和 element-plus 的表单设计器.
#原作者:(lucky7)https://gitee.com/loogn/element-plus-form-designer
#基于原来的基础上做的修改 ##源代码git:https://gitee.com/roffer-d/vue3-form-designer.git
包含三个组件 FormDesigner、FormRenderer 和 FormViewer. FormDesigner 组件用于设计表单,FormRenderer 组件用于呈现表单组件和获取表单提交数据,FormViewer 组件查看数据。
npm i vue3-form-designer
FormDesigner 使用
setup代码:
import { reactive } from "vue";
import { FormDesigner } from "vue3-form-designer";
import "vue3-form-designer/dist/style.css";
let data = reactive({});
//上传配置
let uploadOptions = {
action: 'http://localhost/UploadFile',
getHeaders: function () {
return { 'token': '123456' };
},
getFileHook: (res) => {
if (res.success) {
return {
name: res.url.substr(res.url.lastIndexOf('/') + 1),
url: res.url
};
} else {
return res.msg;
}
}
}
// 默认控件配置
let controlGroups = [
{
name: '基础组件',
controls: ['input', 'textarea', 'inputnumber', 'select', 'radio', 'checkbox',
'rate', 'color', 'date', 'time', 'switch', 'slider', 'text', 'html', 'link', 'divider']
},
{
name: '高级组件',
controls: ['subForm','upload', 'uploadImage', 'region', 'cascader', 'editor','table','tab','geographicalPosition']
},
{
name: '个性化组件',
controls: [
'position',
'licenseDistinguish',
'businessLicenseDistinguish',
'faceDistinguish',
'voiceToText',
'licensePlateDistinguish',
'idCardDistinguish',
'currencyOcr','autograph',
'qrcode','code32','txcode',
]
}
];
// 英文值下拉数据,如果有长度,则是下拉,没有该数据则是输入框
const enData = {
label:'label',//指定显示的key
value:'value',//指定v-model的key
options:[
{label: '选择1',value: '1'},
{label: '选择2',value: '2'}
]//数据集合
}
//自定义表单项按钮点击事件
function itemCustomButtonClick(element) {
console.log(element)
}
//删除表单元素
const deleteItem = (element)=>{
console.log('删除表单元素:',element)
}
//复制表单元素
const copyItem = (element)=>{
console.log('复制表单元素:',element)
}
###若没有能满足需求的组件,可以向表单设计器传入自定义组件:
import test1 from './components/custom/test1'
import test2 from './components/custom/test2'
//自定义组件
const customComponents = [
{
groupName: '自定义组件1',
components: {test1,test2}
},
{
groupName: '自定义组件2',
components: {test1,test2}
}
]
####将自定义组件挂在上去
<FormDesigner ... :customComponents="customComponents">
test1、test2分别为目录,该目录下包含:
index.js 控制器,定义组件的所有属性内容
PropsEditor.vue 定义组件的属性配置项
Renderer.vue 拖拽该组件后呈现的内容
Viewer.vue 预览内容
###index.js
import Renderer from "./Renderer.vue";
import PropEditor from "./PropsEditor.vue";
import Viewer from './Viewer.vue';
class Control {
constructor(props) {
this.type = 'test';
this.name = '测试组件';
this.key = Date.now();
this.id = this.type + "_" + this.key;
this.lock = false;
this.dataType = 'string';
this.props = {
type: 'test',
width: 12,
showLabel: true,
labelWidth: undefined,
label: '测试组件',
enName: '', // 英文名称
inputType: 'text', //类型
defaultValue: '',
placeholder: '',
required: false,
...props
};
this.rules = [
{message: '必填字段', required: !!props?.required}
]
}
}
Control.type = "test";
Control.label = "测试组件";
Control.icon = "https://t7.baidu.com/it/u=1819248061,230866778&fm=193&f=GIF";
export default {Control, Renderer, PropEditor, Viewer};
###PropsEditor.vue
<script setup>
let props = defineProps({
control: Object,
formProps: Object,
enData: Object
})
function requiredChange(value) {
props.control.rules[0].required = value;
}
function requiredMessageChange(value) {
props.control.rules[0].message = value;
}
</script>
<template>
<el-form label-width="90px">
<el-form-item label="中文名称">
<el-input v-model="control.props.label" placeholder="请输入中文名称" :disabled="control.props.disabled"></el-input>
</el-form-item>
<el-form-item label="填写提示">
<el-input v-model="control.props.placeholder" placeholder="请输入填写提示"></el-input>
</el-form-item>
<el-form-item label="描述信息">
<el-input type="textarea" rows="5" v-model="control.props.remark" placeholder="请输入描述信息"></el-input>
</el-form-item>
<el-form-item label="是否必填">
<el-switch @change="requiredChange" v-model="control.props.required"></el-switch>
</el-form-item>
<el-form-item label="必填提示" v-if="control.props.required">
<el-input @change="requiredMessageChange" v-model="control.props.requiredMessage"></el-input>
</el-form-item>
</el-form>
</template>
###Renderer.vue
<script setup>
defineProps({
control: Object,
model: Object,
})
</script>
<template>
<el-radio-group v-if="model" v-model="model[control.id]" size="large">
<el-radio-button label="New York" />
<el-radio-button label="Washington" />
<el-radio-button label="Los Angeles" />
<el-radio-button label="Chicago" />
</el-radio-group>
<el-radio-group v-else v-model="control.props.defaultValue" size="large">
<el-radio-button label="New York" />
<el-radio-button label="Washington" />
<el-radio-button label="Los Angeles" />
<el-radio-button label="Chicago" />
</el-radio-group>
</template>
###Viewer.vue
<script setup>
defineProps({
control: Object,
model: Object,
})
</script>
<template>
<div>{{ model[control.id] }} </div>
</template>
模板代码:
<div class="h-full w-full">
<FormDesigner
:controlGroups="controlGroups"
:uploadOptions="uploadOptions"
:enData="enData"
:formData="data"
:customComponents="customComponents"
@deleteItem="deleteItem" @copyItem="copyItem">
<template #button>
<el-button text type="primary" @click="releaseForm">
<el-icon><NameIcon name="upload"/></el-icon>
<span>发布</span>
</el-button>
</template>
<template #action="{data}">
<el-icon @click.stop="itemCustomButtonClick(data)">
<NameIcon name="editor" style="color:#fff"></NameIcon>
</el-icon>
</template>
</FormDesigner>
</div>
FormDesigner 组件会是百分之百宽高,大小控制父容器即可。
说明:
formData默认值为:
{
"controls": [],
"props": {
"labelPosition": "right",
"labelWidth": 100,
"size": "default",
"customClass": "",
"cols": 12
}
}
controls里每个元素大概是这样的格式,以 select 为例子:
{
"type": "select",
"name": "下拉选择",
"key": "qFahSi153",
"id": "select_qFahSi153",
"lock": false,
"dataType": "string",
"props": {
"width": 12,
"showLabel": true,
"labelWidth": null,
"label": "下拉选择",
"defaultValue": "",
"placeholder": "请选择",
"required": false,
"requiredMessage": "必填字段",
"disabled": false,
"clearable": true,
"filterable": true,
"customClass": "",
"showOptionLabel": false,
"options": [
{
"value": "值1",
"label": "选项1"
},
{
"value": "值2",
"label": "选项2"
}
]
},
"rules": [
{
"message": "必填字段",
"required": false
}
]
}
其中的 lock
属性,用于再次编辑的时候,如果要阻止组件删除,可以设置为true
。
uploadOptions说明:
- action 表单内上传组件的上传地址。
- getHeaders 一个方法,返回自定义上传头内容。
- getFileHook 一个方法,自定义从action返回结果中获取文件信息,成功返回
{name:'文件名称',url:'文件地址'}
,失败返回错误信息字符串。
FormRenderer 使用
setup js代码
import { reactive ,ref } from 'vue';
import { FormRenderer } from 'vue3-form-designer';
import "vue3-form-designer/dist/style.css";
let data = reactive({
formData: {},
formModel: {}
})
let formRenderer=ref(null);
//formData 来自 FormDesigner 组件,意义相同,用于构建表单结构
//formModel 为表单数据,应该来自后台数据,大概是这样:
/*
{
"select_qFahSi153": "值1",
"input_t6ciGfNlv": "12",
"checkbox_la0CN3uuA": [
"值1","值2"
]
}
*/
模板代码:
<FormRenderer
ref="formRenderer"
:formData="data.formData"
:formModel="data.formModel"
/>
FormRenderer 公开的 el-form 的几个方法:
- validate 对整个表单作验证。
- resetFields 对整个表单进行重置,将所有字段值重置为初始值并移除校验结果
- scrollToField 滚动到指定表单字段
- clearValidate 清理指定字段的表单验证信息
具体参考 element-plus 官方文档: https://element-plus.gitee.io/zh-CN/component/form.html#form-%E6%96%B9%E6%B3%95
FormViewer 使用
属性和 FormRenderer 相同。