当我们在后台管理系统中遇到很多表单需要填写的时候 使用el-from一行一行写出来 会导致代码又臭又长 难以维护 并且代码体积会非常大 现在可以看下面的代码开始操作了!
先看图
看到这里可能已经有朋友想起来用饿了么官网提供的el-form组件开始搓了 看代码
肯定是没问题的 但是想一下 如果这种表单 在一个页面同时出现N个类似的 或者在N个页面都需要这样的表单输入 怎么办呢 疯狂的定义el-form-item和校验规则疯狂的CV吗 肯定是不符合我们干完活想摸摸鱼的习惯了 此时此刻就可以看一下这个动态生成了
这里的关键内容是提前定义好一个el-form的HTML结构 然后准备一个json定义我们的表单内容 然后交给表单组件渲染就OK了 看代码
首先看我们的组件页面
<template>
<div>
<el-form
:model="ruleForm"
:rules="formRules"
ref="ruleForm"
:label-width="labelWidht ? labelWidht + 'px' : '180px'"
class="demo-ruleForm"
:disabled="isCheck"
style
>
<div class="item_content">
<el-row>
<el-col
:span="item.span ? item.span : 8"
v-for="(item, index) in formDate"
:key="index"
>
<el-form-item
:label="item.label + ':'"
:prop="item.prop"
v-if="item.type == 'input'"
>
<el-input
v-model="ruleForm[item.prop]"
style="width: 100%"
:value="item.defaultValue ? item.defaultValue : ''"
:placeholder="item.placeholder"
@input="handleInput(index, item.prop, $event)"
:maxlength="item.maxlength"
:disabled="item.disabled || false"
:ref="'popoverRef_' + index"
:rows="item.row ? item.row : 1"
></el-input>
</el-form-item>
<el-form-item
:label="item.label + ':'"
:prop="item.prop"
v-if="item.type == 'date'"
>
<el-date-picker
v-model="ruleForm[item.prop]"
type="daterange"
range-separator="至"
start-placeholder="开始日期"
end-placeholder="结束日期"
style="width: 90%"
:disabled="item.disabled || false"
></el-date-picker>
</el-form-item>
<el-form-item
:label="item.label + ':'"
:prop="item.prop"
v-if="item.type == 'select'"
>
<div style="display: flex; justify-content: space-between">
<el-select
v-model="ruleForm[item.prop]"
placeholder="请选择"
@change="selectChange(item, $event)"
:disabled="item.disabled || false"
style="width: 100%"
:style="{
width:
item.prop == 'thirdFrequency' &&
ruleForm[item.prop] == '其他'
? '30%'
: '100%',
}"
:multiple="item.multiple"
>
<el-option
v-for="item1 in item.options"
:key="item1.value"
:label="item1.label"
:value="item1.value"
></el-option>
</el-select>
</div>
</el-form-item>
<el-form-item
:label="item.label + ':'"
:prop="item.prop"
v-if="item.type == 'datePick'"
>
<el-date-picker
v-model="ruleForm[item.prop]"
type="date"
placeholder="选择日期"
style="width: 100%"
:disabled="item.disabled || false"
value-format="yyyy-MM-dd"
></el-date-picker>
</el-form-item>
<el-form-item
:label="item.label + ':'"
:prop="item.prop"
v-if="item.type == 'datePickRange'"
>
<el-date-picker
style="width: 100%"
v-model="ruleForm[item.prop]"
type="daterange"
range-separator="至"
start-placeholder="开始日期"
end-placeholder="结束日期"
unlink-panels
:disabled="item.disabled || false"
value-format="yyyy-MM-dd"
></el-date-picker>
</el-form-item>
</el-col>
<el-col>
<slot name="customItem"></slot>
</el-col>
</el-row>
</div>
</el-form>
</div>
</template>
<script>
export default {
props: {
formDate: {
type: Array,
default: () => [],
},
labelWidht: {
type: Number,
},
isCheck: {
type: Boolean,
default: false,
},
},
data() {
return {
ruleForm: {}, // 初始化为空对象,以便动态绑定属性
formRules: {}, // 用于存放动态生成的校验规则
};
},
watch: {
formDate: {
handler(newval) {
if (newval) {
// console.log("我被通知修改了");
this.initForm();
}
},
deep: true,
},
},
mounted() {
this.initForm();
},
methods: {
/**
考虑到很多内容应会根据select的变化而变化 所以这里添加了一个回调函数 直接在JSON中定义好函数名
然后就可以在组件中使用了
*/
selectChange(item, event) {
if (item.cb) {
item.cb(this.ruleForm[item.prop], event);
}
this.$emit("redraw");
},
initForm() {
// 初始化表单数据
const initialData = {};
this.formDate.forEach((item) => {
if (item.defaultValue) {
initialData[item.prop] = item.defaultValue;
}
});
this.ruleForm = initialData;
// 生成校验规则
this.generateFormRules();
},
generateFormRules() {
const rules = {};
this.formDate.forEach((item) => {
if (item.rules && item.rules.length > 0) {
rules[item.prop] = item.rules.map((rulesItem) => {
return {
required: true,
message: `${item.label}${rulesItem}`,
trigger: "blur",
};
});
}
});
this.formRules = rules;
this.$nextTick(() => {
// 生成之后需要清空一下 否则会触发校验
this.$refs["ruleForm"].clearValidate();
});
},
handleInput(index, prop, event) {
this.$forceUpdate();
},
submitForm(status) {
let formData = {};
this.$refs.ruleForm.validate((valid) => {
if (valid) {
formData = this.ruleForm;
}
});
return formData;
},
resetForm() {
this.$refs.ruleForm.resetFields();
},
clearRule() {
this.$refs.ruleForm.clearValidate();
},
setOther(val) {
this.$set(this.ruleForm, "thirdFrequencyOther", val);
},
},
};
</script>
<style scoped lang="scss">
.demo-ruleForm {
padding: 6px 0 15px 0;
font-weight: normal;
::v-deep label {
font-weight: 500 !important;
}
}
.tip_icon {
position: absolute;
right: -2%;
top: -18%;
background: #fff;
}
.item_content {
// width: 90%;
}
.item_btn {
width: 10%;
line-height: 40px;
display: flex;
align-items: flex-end;
justify-content: flex-end;
}
::v-deep {
.el-form-item {
margin-top: 10px !important;
margin-bottom: 10px;
}
}
</style>
引入组件
<template>
<div class="form_container">
<prodcutForm :labelWidht="180" :formDate="formData" ref="product">
</prodcutForm>
<div style="text-align: center">
<el-button type="primary" @click="submit">确定</el-button>
</div>
</div>
</template>
<script>
import formData from "./mixin.js";
import prodcutForm from "@/components/customForm";
export default {
mixins: [formData],
components: { prodcutForm },
data() {
return {};
},
methods: {
submit() {
const data = this.$refs.product.submitForm();
console.log(data);
},
},
mounted() {},
};
</script>
<style lang="scss" scoped>
.form_container {
background-color: #fff;
padding: 20px;
}
</style>
JSON数据
这里的JSON数据我使用了mixin的方法 嫌麻烦的同学也可以直接在data中写入
export default {
data() {
return {
formData: [
{
prop: "expectedProductName",
label: "产品名称",
defaultValue: "",
placeholder: "请输入产品名称?",
type: "input",
rules: ["不能为空"],
},
{
prop: "keyCustomerGroup",
label: "产品面向的主要客群",
defaultValue: "",
placeholder: "是否有限定客群?",
type: "input",
rules: ["不能为空"],
},
{
prop: "pricing",
label: "产品定价",
defaultValue: "",
placeholder: "如价格固定20000",
type: "input",
rules: ["不能为空"],
},
{
prop: "contentsInclude",
label: "产品包含什么内容",
defaultValue: "",
placeholder: "请问要销售什么产品",
type: "input",
},
{
prop: "salesChannels",
label: "产品的销售渠道",
defaultValue: "",
placeholder: "预计在哪个平台/渠道销售",
type: "input",
},
{
prop: "invoiceRequire",
label: "发票要求",
defaultValue: "",
placeholder: "是否需要提供发票",
type: "input",
},
{
prop: "saleType",
label: "产品销售方式",
type: "select",
options: [
{
label: "线上销售",
value: "线上销售",
},
{
label: "线下销售",
value: "线下销售",
},
],
defaultValue: "",
},
{
prop: "payMode",
label: "产品支付方式",
type: "select",
multiple: true,
options: [
{
label: "微信",
value: "微信",
},
{
label: "支付宝",
value: "支付宝",
},
{
label: "银行卡",
value: "银行卡",
},
{
label: "现金",
value: "现金",
},
],
cb: (val) => {
this.changePayMode(val);
},
defaultValue: "",
},
{
prop: "saleTime",
label: "产品销售日期",
type: "datePickRange",
defaultValue: "",
},
],
};
},
};
觉得有用的可以点个赞嗷 谢谢各位!