最近遇到一个需要超级写超级多字段的表单,初略计算大概四十来个吧字段吧,/(ㄒoㄒ)/~~,这也太麻烦了,想了想能不能简单封装一下,找到了个巨人,嗯哼,就踩一下吧
参考文章: Vue3.0 根据JSON对象生成指定form表单 上面文章是vue3的,逻辑都一样。以下是vue2 我的写法
1.定义 formTemplate.vue
<template>
<el-col v-if="isCol" :span="colSpan">
<div v-if="isForm">
<el-form-item :prop="prop" :label="label">
<component
:is="isCom"
:config="config"
v-model="templateValue"
@change="change"
/>
</el-form-item>
</div>
<div v-else>
<component
:is="isCom"
:config="config"
v-model="templateValue"
@change="change"
/>
</div>
</el-col>
<div v-else>
<div v-if="isForm">
<el-form-item :prop="prop" :label="label">
<component
:is="isCom"
:config="config"
v-model="templateValue"
@change="change"
/>
</el-form-item>
</div>
<div v-else>
<component
:is="isCom"
:config="config"
v-model="templateValue"
@change="change"
/>
</div>
</div>
</template>
<script>
import formInput from "./formInput";
import formSelect from "./formSelect"
/**
* @author BlackKey
* @params value 双向绑定值
* @params colSpan 布局占位
* @params isCol 是否启用布局
* @params isForm 是否用form包裹
* @params label 标题
* @params prop model的键名
* @params isCom 需要的生成的组件
* @params config 组件对应的配置文件
* @desc form表单默认格式
*/
export default {
components: {
formInput,
formSelect
},
model: {
prop: "value",
event: "change",
},
props: {
colSpan: {
type: Number,
default: 6,
},
isCol: {
type: Boolean,
default: true,
},
isForm: {
type: Boolean,
default: true,
},
label: {
type: String,
default: "",
},
prop: {
type: String,
default: "",
},
isCom: {
type: String,
default: "formInput",
},
value: {
type: [String, Number, Object, Array],
default: "",
},
config: {
type: Object,
default: () => ({}),
},
},
methods: {
change(data) {
this.$emit("change", data);
}
},
computed: {
templateValue: {
get() {
return this.value;
},
set(val) {
this.$emit("change", val);
},
}
},
};
</script>
<style lang="less" scoped></style>
2. 输入框组件 formInput.vue
<template>
<el-input
v-model="inputValue"
:placeholder="defaultConfig.placeholder"
:clearable="defaultConfig.clearable"
:disabled="defaultConfig.disabled"
:type="defaultConfig.type"
:maxlength="defaultConfig.maxlength"
:autosize="defaultConfig.autosize"
/>
</template>
<script>
/**
* @author BlackKey
* @params value 双向绑定值
* @params placeholder 输入框占位符文本
* @params type 输入框类型
* @params maxlength 最大长度
* @params disabled 是否禁用
* @params size 输入框尺寸
* @params autosize textarea 高度是否自适应,仅 type 为 'textarea' 时生效。
* @params clearable 是否展示清空按钮
* @desc 输入框
*/
export default {
props: {
config: {
type: Object,
default: () => ({ }),
},
value: {
type: [String, Number, Object, Array],
default: "",
},
},
data(){
return {
inputValue: '',
defaultConfig: {
placeholder: "",
type: "text",
maxlength: "",
disabled: false,
size: "",
autosize: false,
clearable: true,
}
}
},
mounted(){
this.inputValue = this.value
this.defaultConfig = {...this.defaultConfig, ...this.config}
},
watch: {
inputValue: {
immediate: true,
handler(newVal, oldVal) {
this.$emit("change", newVal);
},
},
},
}
</script>
3. 下拉选择框 formSelect.vue
<template>
<el-select
v-model="selectValue"
:clearable="defaultConfig.clearable"
:placeholder="defaultConfig.placeholder"
:disabled="defaultConfig.disabled"
:size="defaultConfig.size"
>
<el-option
v-for="item in defaultConfig.options"
:key="item[defaultConfig.labelKey]"
:label="item[defaultConfig.labelKey]"
:value="item[defaultConfig.valueKey]"
></el-option>
</el-select>
</template>
<script>
/**
* @author BlackKey
* @params modelValue 双向绑定值
* @params placeholder 输入框占位符文本
* @params disabled 是否禁用
* @params size 输入框尺寸
* @params clearable 是否展示清空按钮
* @params options 下拉框的值
* @params dataType 预先设定好的枚举
* @params labelKey 下拉框labelKey
* @params valueKey 下拉框valueKey
* @desc 下拉框
*/
export default {
props: {
config: {
type: Object,
default: () => ({}),
},
value: {
type: [String, Number, Object, Array],
default: "",
},
},
data() {
return {
selectValue: "",
source: [
{
label: "男",
value: "man",
},
{
label: "女",
value: "woman",
},
],
defaultConfig: {
placeholder: "",
disabled: false,
size: "",
clearable: true,
options: [],
dataType: "",
labelKey: "label",
valueKey: "value",
}
};
},
mounted() {
this.selectValue = this.value
this.defaultConfig = {...this.defaultConfig, ...this.config}
// Object.keys(this.config).forEach(key=>{this.defaultConfig[key]=this.config[key]})
},
watch: {
selectValue: function (newVal, oldVal) {
this.$emit("change", newVal);
}
}
};
</script>
使用方法
<template>
<div class="content">
<div class="query">
<div class="formWrap">
<el-form
:model="form"
:rules="rules"
ref="formRef"
label-width="120px"
>
<el-row :gutter="20">
<form-template
v-for="item in formTemplateData"
:key="item.label"
:label="item.label"
:prop="item.prop"
:config="item.config"
:isCom="item.isCom"
v-model="item.value"
></form-template>
<el-col :span="24">
<div class="btn">
<el-button type="primary" @click="search">查询</el-button>
</div>
</el-col>
</el-row>
</el-form>
</div>
</div>
</div>
</template>
<script>
import formTemplate from "../components/formTemplate";
import formInput from "../components/formInput";
import formSelect from "../components/formSelect";
export default {
components: {
formTemplate,
formInput,
formSelect,
},
data() {
return {
form: {
dataId: "123123123123",
orgLicense: "rrrr1234",
orgType: "99",
address: "测试地址110",
postalCode: "1",
workNum: 1,
orgLicenseTime: "2019-12-21 10:30:00",
economicOwnership: "310",
fixedAssets: 1,
unitArea: 0,
totalBuildingArea: 0,
monitorLevel: "1",
gridId: "",
maintenanceUnitId: "",
checkUnitId: "1",
constructionUnitId: "1",
monitorType: "2",
monitorCenterId: "1278158407189680128",
fireManageId: "JXXF1",
orgTel: "13256781234",
networkStatus: "1",
accessDate: "2019-12-21 10:30:00",
fireSafePerson: "测试人1",
fireSafePersonId: "1",
fireSafePersonTel: "18100000001",
fireSafeManager: "1",
fireSafeManagerId: "1",
fireSafeManagerTel: "1",
fptimeFireManager: "1",
fptimeFireManagerId: "1",
fptimeFireManagerTel: "1",
corporator: "1",
corporatorId: "1",
corporatorTel: "1",
fireSupervisor: "1",
fireSupervisorTel: "1",
companyProfile: "",
informationPushSignature: "",
containSystem: "1",
scopeOfBusiness: "1",
rescueDepartment: "1",
commercialProjects: "1",
contractualStatus: "1",
company: {
companyName: "第三方-拓宝",
fullName: "第三方-拓宝",
area: {
areaCode: "360100",
areaName: "南昌市",
},
industryType: "6",
industryDept: "1",
lng: 114.47335,
lat: 30.452798,
},
},
formTemplateData: [
{
label: "dataId",
value: "",
prop: "dataId",
config: {
placeholder: "请输入dataId",
},
},
{
label: "orgLicense",
value: "",
prop: "orgLicense",
config: {
placeholder: "请输入orgLicense",
},
},
{
label: "orgType",
value: "",
prop: "orgType",
config: {
placeholder: "请输入orgType",
},
},
{
label: "address",
value: "",
prop: "address",
config: {
placeholder: "请输入address",
},
},
{
label: "postalCode",
value: "",
prop: "postalCode",
config: {
placeholder: "请输入postalCode",
},
},
{
label: "workNum",
value: "",
prop: "workNum",
config: {
placeholder: "请输入workNum",
},
},
{
label: "orgLicenseTime",
value: "",
prop: "orgLicenseTime",
config: {
placeholder: "请输入orgLicenseTime",
},
},
{
label: "economicOwnership",
value: "",
prop: "economicOwnership",
config: {
placeholder: "请输入economicOwnership",
},
},
{
label: "fixedAssets",
value: "",
prop: "fixedAssets",
config: {
placeholder: "请输入fixedAssets",
},
},
{
label: "unitArea",
value: "",
prop: "unitArea",
config: {
placeholder: "请输入unitArea",
},
},
{
label: "totalBuildingArea",
value: "",
prop: "totalBuildingArea",
config: {
placeholder: "请输入totalBuildingArea",
},
},
{
label: "monitorLevel",
value: "",
prop: "monitorLevel",
config: {
placeholder: "请输入monitorLevel",
},
},
{
label: "gridId",
value: "",
prop: "gridId",
config: {
placeholder: "请输入gridId",
},
},
{
label: "maintenanceUnitId",
value: "",
prop: "maintenanceUnitId",
config: {
placeholder: "请输入maintenanceUnitId",
},
},
{
label: "checkUnitId",
value: "",
prop: "checkUnitId",
config: {
placeholder: "请输入checkUnitId",
},
},
{
label: "constructionUnitId",
value: "",
prop: "constructionUnitId",
config: {
placeholder: "请输入constructionUnitId",
},
},
{
label: "monitorType",
value: "",
prop: "monitorType",
config: {
placeholder: "请输入monitorType",
},
},
{
label: "monitorCenterId",
value: "",
prop: "monitorCenterId",
config: {
placeholder: "请输入monitorCenterId",
},
},
{
label: "fireManageId",
value: "",
prop: "fireManageId",
config: {
placeholder: "请输入fireManageId",
},
},
{
label: "orgTel",
value: "",
prop: "orgTel",
config: {
placeholder: "请输入orgTel",
},
},
{
label: "networkStatus",
value: "",
prop: "networkStatus",
config: {
placeholder: "请输入networkStatus",
},
},
{
label: "accessDate",
value: "",
prop: "accessDate",
config: {
placeholder: "请输入accessDate",
},
},
{
label: "fireSafePerson",
value: "",
prop: "fireSafePerson",
config: {
placeholder: "请输入fireSafePerson",
},
},
{
label: "fireSafePersonId",
value: "",
prop: "fireSafePersonId",
config: {
placeholder: "请输入fireSafePersonId",
},
},
{
label: "fireSafePersonId",
value: "",
prop: "fireSafePersonId",
config: {
placeholder: "请输入fireSafePersonId",
},
},
{
label: "fireSafePersonTel",
value: "",
prop: "fireSafePersonTel",
config: {
placeholder: "请输入fireSafePersonTel",
},
},
{
label: "fireSafeManagerId",
value: "",
prop: "fireSafeManagerId",
config: {
placeholder: "请输入fireSafeManagerId",
},
},
{
label: "fireSafeManager",
value: "",
prop: "fireSafeManager",
config: {
placeholder: "请输入fireSafeManager",
},
},
{
label: "fireSafeManagerTel",
value: "",
prop: "fireSafeManagerTel",
config: {
placeholder: "请输入fireSafeManagerTel",
},
},
{
label: "fptimeFireManager",
value: "",
prop: "fptimeFireManager",
config: {
placeholder: "请输入fptimeFireManager",
},
},
{
label: "fptimeFireManagerId",
value: "",
prop: "fptimeFireManagerId",
config: {
placeholder: "请输入fptimeFireManagerId",
},
},
{
label: "corporator",
value: "",
prop: "corporator",
config: {
placeholder: "请输入corporator",
},
},
{
label: "fptimeFireManagerTel",
value: "",
prop: "fptimeFireManagerTel",
config: {
placeholder: "请输入fptimeFireManagerTel",
},
},
{
label: "corporatorId",
value: "",
prop: "corporatorId",
config: {
placeholder: "请输入corporatorId",
},
},
{
label: "corporatorTel",
value: "",
prop: "corporatorTel",
config: {
placeholder: "请输入corporatorTel",
},
},
{
label: "fireSupervisor",
value: "",
prop: "fireSupervisor",
config: {
placeholder: "请输入fireSupervisor",
},
},
{
label: "fireSupervisorTel",
value: "",
prop: "fireSupervisorTel",
config: {
placeholder: "请输入fireSupervisorTel",
},
},
{
label: "companyProfile",
value: "",
prop: "companyProfile",
config: {
placeholder: "请输入companyProfile",
},
},
{
label: "informationPushSignature",
value: "",
prop: "informationPushSignature",
config: {
placeholder: "请输入informationPushSignature",
},
},
{
label: "containSystem",
value: "",
prop: "containSystem",
config: {
placeholder: "请输入containSystem",
},
},
{
label: "scopeOfBusiness",
value: "",
prop: "scopeOfBusiness",
config: {
placeholder: "请输入scopeOfBusiness",
},
},
{
label: "rescueDepartment",
value: "",
prop: "rescueDepartment",
config: {
placeholder: "请输入rescueDepartment",
},
},
{
label: "commercialProjects",
value: "",
prop: "commercialProjects",
config: {
placeholder: "请输入commercialProjects",
},
},
{
label: "contractualStatus",
value: "",
prop: "contractualStatus",
config: {
placeholder: "请输入contractualStatus",
},
},
{
label: "companyName",
value: "",
prop: "company.companyName",
config: {
placeholder: "请输入companyName",
},
},
{
label: "fullName",
value: "",
prop: "company.fullName",
config: {
placeholder: "请输入fullName",
},
},
{
label: "industryType",
value: "",
prop: "company.industryType",
config: {
placeholder: "请输入industryType",
},
},
{
label: "industryDept",
value: "",
prop: "company.industryDept",
config: {
placeholder: "请输入industryDept",
},
},
{
label: "lng",
value: "",
prop: "company.lng",
config: {
placeholder: "请输入lng",
},
},
{
label: "lat",
value: "",
prop: "company.lat",
config: {
placeholder: "请输入lat",
},
},
{
label: "areaCode",
value: "",
prop: "company.area.areaCode",
config: {
placeholder: "请输入areaCode",
},
},
{
label: "areaName",
value: "",
prop: "company.area.areaName",
config: {
placeholder: "请输入areaName",
},
},
],
rules: {
dataId: [{ required: true, message: '请填写', trigger: 'change' }]
}
};
},
methods: {
search() {
this.formTemplateData.forEach((val) => {
// 组装数据
let keysArr = val.prop.split(".");
this.setValueByKeys(this.form, keysArr, val.value);
// this.form[val.prop] = val.value;
});
this.$refs.formRef.validate((valid)=>{
if(valid){
console.log('-----------',valid)
// this.onSubmit()
}
})
// console.log(this.form);
},
/**
* obj 当前层的对象
* keysArr 每层key的数组 例如 company.companyName
* value 要赋的值
*/
setValueByKeys(obj, keysArr, value) {
if (keysArr.length == 1) {
obj[keysArr[0]] = value;
} else {
let p = keysArr[0];
keysArr.shift();
return this.setValueByKeys(obj[p], keysArr, value);
}
},
},
};
</script>
<style scoped lang="scss">
.flex {
display: flex;
justify-content: space-between;
align-items: center;
}
.content {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
h3 {
font-size: 1.2em;
line-height: 1.43;
margin-top: 20px;
}
.notice {
.text {
padding: 16px;
overflow: auto;
line-height: 1.45;
background-color: #f7f7f7;
border: 0;
border-radius: 3px;
}
}
.query{
.formWrap{
max-height: 320px;
overflow: hidden auto;
}
}
.result {
flex: 1;
display: flex;
flex-direction: column;
overflow: hidden;
.code {
flex: 1;
overflow-y: auto;
width: 100%;
background: rgb(54, 61, 68);
}
.text {
word-break: break-all;
color: #c3c6c4;
}
}
}
.demo-ruleForm {
display: flex;
flex-direction: row;
gap: 20px;
flex-wrap: wrap;
::v-deep {
.el-form-item {
width: 24%;
}
.el-select {
width: 100%;
}
}
}
</style>
注意事项: 使用时记得用el-form和el-row包裹一下,因为默认使用布局和form包裹住