技术栈:vue2+ js + webpack
需求:
利用数据渲染表单,实现代码的精简化及效率的提升。
效果图:
封装的组件:
<div v-if="formConfig">
<el-form
v-bind="$attrs"
ref="formDom"
:model="formData"
:rules="formRules"
:inline="inline"
:label-width="labelWidth"
:label-position="labelPosition"
>
<el-form-item
v-for="(item, key, index) in formConfig"
:key="key"
:label="item.label"
:label-width="item.labelWidth || '61px'"
:prop="key"
:style="item.style"
v-if="!item.hide"
>
<!-- 只列出focus blur change事件举例,更多事件可以自行添加绑定 -->
<el-input
v-bind="$attrs"
v-if="item.type === 'input'"
v-model="formData[key]"
:disabled="item.disabled"
:type="item.inputType ? item.inputType : 'text'"
:placeholder="item.placeholder || `请输入${item.label}`"
clearable
@focus="e => issueEvent(e, item.onFocus)"
@blur="e => issueEvent(e, item.onBlur)"
@change="e => issueEvent(e, item.onChange)"
/>
<el-select
v-if="item.type === 'select'"
v-model="formData[key]"
clearable
:disabled="item.disabled"
:placeholder="item.placeholder || `请选择${item.label}`"
:multiple="item.multiple"
:filterable="item.filterable"
:max-tag-count="item.max_tag_count"
style="width:100%"
@change="e => issueEvent(e, item.onChange)"
>
<el-option
v-for="list in item.options"
:key="list.value"
:value="list.value"
:label="list.label"
>
</el-option>
</el-select>
<el-cascader
v-if="item.type === 'cascader'"
v-model="formData[key]"
:disabled="item.disabled"
:options="item.options"
:show-all-levels="false"
style="width:100%"
:placeholder="item.placeholder || `请输入${item.label}`"
:props="item.props"
@change="e => issueEvent(e, item.onChange)"
></el-cascader>
<el-date-picker
v-if="item.type === 'dateTime'"
v-model="formData[key]"
:picker-options="pickerOptions"
:type="item.dateType ? item.dateType : 'month'"
:key="item.dateType ? item.dateType : 'month'"
:placeholder="item.placeholder || `请选择${item.label}`"
:value-format="item.format"
></el-date-picker>
<slot name="form" :item="item" :from="formData[key]" />
<div>
<el-button
v-if="item.type === 'confirm'"
type="primary"
icon="el-icon-search"
:loading="item.isSearching"
@click="submit"
>
{{ item.text ? item.text : "查询" }}
</el-button>
<el-button
v-if="item.type === 'reset'"
icon="el-icon-refresh"
@click="reset"
>
{{ item.text ? item.text : "重置" }}
</el-button>
<el-button
v-if="item.type === 'export'"
class="downloadbtn"
@click="handleExport"
>
<svg-icon icon-class="ic_export" class="tablesvgicon"></svg-icon>
{{ item.text ? item.text : "导出" }}
</el-button>
<slot name="button" :item="item" />
</div>
</el-form-item>
</el-form>
</div>
</template>
<script>
export default {
name: "customForm",
props: {
// 表单项是否行内显示
inline: {
type: Boolean,
default: true
},
// 表单项配置
formConfig: {
type: Object,
default: () => {}
},
// 表单项数据
formDataInit: {
type: Object,
default: () => {}
},
// 表单标签宽度
labelWidth: {
type: [Number, String],
default: "61"
},
// 表单标签位置,默认左侧
labelPosition: {
type: String,
default: "left"
},
// 表单校验规则
formRules: {
type: Object,
default: () => {}
}
},
data() {
return {
formData: this.formDataInit
};
},
methods: {
//重点在issueEvent函数,可以给事件绑定一个空函数避免报错,如果有外部传入的自定义函数则返回这个函数
/*组件内函数负责分发表单项事件 */
issueEvent(value, mouseEvent) {
if (mouseEvent) {
return mouseEvent(value);
}
},
submit() {
this.$emit("submit");
},
reset() {
this.$refs.formDom.resetFields();
this.$emit("reset");
},
handleExport() {
this.$emit("handleExport");
}
}
};
</script>
<style lang="scss" scoped>
/deep/ .el-cascader--medium {
line-height: 28px;
}
</style>
组件的运用:
<template>
<div>
<div class="search-box xl-querybox marginbottom15 borderRadius1 ">
<!-- 这里是测试页 测试引入组件 -->
<BaseFrom
:formDataInit="formDataInit"
:form-config="formConfig"
:form-rules="formRules"
@submit="getList"
>
<template #form="{from,item}">
<div v-if="item.type === 'tab'">
<el-radio-group v-model="from" @change="handleQuery($event, from)">
<el-radio-button :label="1">日</el-radio-button>
<el-radio-button :label="2">月</el-radio-button>
<el-radio-button :label="3">年</el-radio-button>
</el-radio-group>
</div>
</template>
<template #button="{item}">
<div v-if="item.type === 'button'">12313</div>
</template>
</BaseFrom>
<!-- 新增编辑的表单 -->
</div>
<div class="edit-from-style">
<BaseFrom
:formDataInit="formDataInit"
:form-config="formConfig2"
:form-rules="formRules"
:inline="false"
@submit="getList"
>
</BaseFrom>
</div>
</div>
</template>
<script>
import BaseFrom from "@/components/BaseFrom";
import { formatDate_y_m_d } from "@/utils/index";
export default {
components: {
BaseFrom
},
data() {
return {
formConfig2: {
id: {
label: "id",
type: "input",
// style: { width: "20%" },
placeholder: "看看提示语",
labelWidth: "null"
},
name: {
label: "name",
type: "input",
placeholder: "看看提示语",
labelWidth: "null"
},
ids: {
label: "项目id",
type: "cascader",
style: { width: "100%" },
props: {
expandTrigger: "hover",
children: "childs",
label: "label",
value: "value"
},
options: [
{ label: "请选择", value: "" },
{ label: "技术", value: "技术" },
{ label: "生活", value: "生活" },
{ label: "其他", value: "其他" }
],
labelWidth: "null"
}
},
/*----------表格头部的查询表单---------- */
isSearching: false, // // 是否查询中
// 表单配置
formConfig: {
id: {
label: "id",
type: "input",
placeholder: "看看提示语"
},
ids: {
label: "项目id",
type: "cascader",
props: {
expandTrigger: "hover",
children: "childs",
label: "label",
value: "value"
},
options: [
{ label: "请选择", value: "" },
{ label: "技术", value: "技术" },
{ label: "生活", value: "生活" },
{ label: "其他", value: "其他" }
]
},
status: {
label: "状态",
type: "select",
// multiple: true, // 是否支持多选
max_tag_count: 1, // 多选时最多显示多少个 tag
options: [
{
label: "数据一",
value: "0"
},
{
label: "数据二",
value: "1"
}
],
onChange: (value, label, arr) => {
console.log(value, label, arr);
if (value == "0") {
this.formConfig["id"].disabled = false;
} else {
this.formConfig["id"].disabled = true;
}
console.log("this.formDataInit", this.formDataInit);
}
},
tab: {
label: "周期",
type: "tab",
labelWidth: "10"
},
time: {
label: "时间",
type: "dateTime"
},
// time1: {
// label: "时间组2件",
// type: "dateTime",
// dateType: "year",
// format: "yyyy-MM-dd",
// labelWidth: "100"
// },
confirm: {
text: "查询", // 按钮文案
type: "confirm",
label: " ",
labelWidth: 0,
isSearching: this.isSearching
},
reset: {
type: "reset"
},
button: {
type: "button"
}
},
// 表单数据
formDataInit: {
id: "",
page_number: 1,
page_size: 10,
time: formatDate_y_m_d(new Date()),
tab: 1
},
// 表单校验规则
formRules: {
id: [
{ required: true, message: "请输入id", trigger: "blur" },
{ min: 3, max: 5, message: "长度在 3 到 5 个字符", trigger: "blur" }
],
status: [{ required: true, message: "请选择", trigger: "change" }]
}
};
},
methods: {
getList() {
console.log("提交了", this.formDataInit);
},
handleQuery($event, from) {
this.formDataInit.tab = from;
console.log("4444", $event, from);
switch (from) {
case 3:
this.formConfig.time.dateType = "year";
this.formConfig.time.format = "yyyy-MM-dd";
this.formConfig.time.placeholder = "选择年";
break;
case 2:
this.formConfig.time.dateType = "month";
this.formConfig.time.format = "yyyy-MM-dd";
this.formConfig.time.placeholder = "选择年月";
break;
case 1:
this.formConfig.time.dateType = "date";
this.formConfig.time.format = "yyyy-MM-dd";
this.formConfig.time.placeholder = "选择年月日";
break;
default:
break;
}
}
}
};
</script>
<style lang="scss" scoped>
.edit-from-style {
/deep/.el-form {
.el-form-item {
height: 60px;
line-height: 60px;
align-items: center;
text-align: center;
justify-content: flex-start;
display: flex;
border: 1px solid #ebeef5;
@include timeAndChooseColor2();
margin-bottom: 0;
&:not(:last-child) {
border-bottom: none;
}
}
.el-form-item__content {
margin-left: 10px !important;
width: 40%;
@media screen and (max-width: 800px) {
width: 66%;
}
}
.el-form-item__label {
width: 210px;
line-height: 58px;
padding-left: 10px;
background-color: #fafafa;
border-right: 1px solid #ebeef5;
&:not(:last-child) {
border-bottom: none;
}
@media screen and (max-width: 800px) {
width: 90px;
}
@include tableBorderColor7();
@include formBox();
// @include bgColor2();
}
}
}
</style>
参考文章:添加链接描述