前言:之前碰到一个需求,一个页面,有16个表单,根据下拉框的值去切换表单,如果页面里一个一个的写,页面太冗长了!秉承一个页面不超过500行的代码风格,我把表单根据element-ui进行了二次封装。
所有的内容都写在了代码中,不懂得地方查看注释🐶🐶
父组件引用:
html部分
<template>
<div class="container">
<h3>form表单封装案例</h3>
<div style="margin: 10px">
根据下拉框的值改变form表单:
<el-select v-model="value" placeHolder="请选择" @change="handleChange">
<el-option
v-for="item in options"
:key="item.value"
:value="item.value"
:label="item.label"
>
</el-option>
</el-select>
</div>
// 仅关注这里即可,上面是表单切换触发的条件
<PublicForm
ref="PublicForm"
:formModel="formObj"
:formItemList="formItemList"
></PublicForm>
</div>
</template>
JS部分
<script>
import PublicForm from './PublicForm';
// ⚠️⚠️⚠️ 注意这里引入了一个js文件,是form表单的配置
import { form1, formList1, form2, formList2 } from './formConfig.js';
export default {
name: 'myForm',
components: { PublicForm },
data() {
return {
value: '1',
options: [
{ value: '1', label: 'Form1表单' },
{ value: '2', label: 'Form2表单' },
],
// ⚠️⚠️⚠️⚠️⚠️⚠️⚠️,注意这里,是父组件传的参数
formObj: form1,
formItemList: formList1,
};
},
methods: {
// 这里是下拉框选择事件,可忽略
handleChange(val) {
// 下拉框的值变化,form表单的内容也变化
switch (val) {
case '1':
// 切换下拉框的选项,form表单的配置随之改变
this.formObj = form1;
this.formItemList = formList1;
break;
case '2':
this.formObj = form2;
this.formItemList = formList2;
break;
default:
break;
}
},
}
};
</script>
❕❕❕form表单配置的js文件,这里注意看
formConfig.js文件
// form表单的所有字段
export const form1 = {
name: '', // 姓名
gender: '1', // 性别 可以配置表单默认值
height: '' // 身高
}
// form表单每个字段对应的配置信息,你是下拉框还是输入框还是单选按钮?在这里配置
export const formList1 = [
{
type: 'input',
label: '姓名',
key: 'name', // 跟上面的姓名字段对应
rules: [{ required: true, message: '请输入姓名', trigger: ['blur', 'change'] }]
},
{
type: 'select',
label: '性别',
key: 'gender',
options: [
{ value: '1', label: '男' },
{ value: '0', label: '女' },
],
},
{
type: 'input',
label: '身高',
key: 'height', // 跟上面的姓名字段对应
rules: [{ required: true, message: '请输入身高', trigger: ['blur', 'change'] }]
},
]
export const form2 = {
targetName: '', // 指标名称
isImportant: '1', // 是否重要 也可以设置默认值
targetDate: '2023-01-01' // 指标日期 也可以设置默认值
}
export const formList2 = [
{
type: 'input',
label: '指标名称',
key: 'targetName',
},
{
type: 'radio',
label: '是否重要',
key: 'isImportant',
options: [
{ value: '1', label: '重要' },
{ value: '0', label: '不重要' },
],
},
{
type: 'time', // 日期组件的话还需要设定timeType ,比如时间范围 daterange
timeType: 'date',
label: '指标日期',
key: 'targetDate',
},
]
子组件:
html部分
<template>
<div>
<el-form
ref="publicFormRef"
:model="formModel"
v-bind="$attrs"
:label-width="formConfig.labelWidth"
>
<el-row>
<el-col :span="item.span || 10" v-for="item in formItemList" :key="item.key">
<template>
<el-form-item
class="list-item-class"
:key="item.key"
:rules="item.rules"
:label="item.label ? item.label + ':' : ''"
:prop="item.key"
>
<!-- 输入框 -->
<el-input
v-if="item.type == 'input'"
:placeholder="item.placeholder || '请输入' + item.label"
v-model="formModel[item.key]"
:type="item.inputType || 'text'"
:maxlength="item.maxlength || 100000"
:minlength="item.minlength || 0"
@input="item.inputEvent && item.inputEvent($event, item.key)"
:show-word-limit="item.limit"
:disabled="item.disabled"
clearable
></el-input>
<!-- 下拉框 -->
<el-select
v-else-if="item.type == 'select'"
v-model="formModel[item.key]"
:placeholder="item.placeholder || '请选择' + item.label"
:disabled="item.disabled"
>
<!-- 这里注意,options的内容需是value和label,如果不是,需要在父组件map处理一下再传,方法如下 -->
<!-- handleOption(options) {
// 假如你的是 id 和 text [{id:1,text:'aa'},{id:2,text:'bb'}] => [{value:1,label:'aa'},{value:2,label:'bb'}]
options.map(obj => {
return { value: obj.id, label: obj.text };
});
}, -->
<el-option
v-for="opt in item.options"
:label="opt.label"
:value="opt.value"
:key="opt.value"
>
</el-option>
</el-select>
<!-- 这里默认的日期格式看自己的项目需求,目前默认 yyyy-MM-dd -->
<!-- 如需添加新功能(例如日期图标 ),请自行设置-->
<el-date-picker
v-else-if="item.type == 'time'"
v-model="formModel[item.key]"
:type="item.timeType"
:unlink-panels="item.unlinkPanels"
:start-placeholder="item.timeType === 'daterange' ? '开始日期' : ''"
:end-placeholder="item.timeType === 'daterange' ? '结束日期' : ''"
:value-format="item.valueFormat || 'yyyy-MM-dd'"
:placeholder="
item.timeType === 'date' ? item.placeholder || '请选择日期' : ''
"
:picker-options="item.pickerOptions || pickerOptions"
>
</el-date-picker>
<!-- 单选按钮 -->
<el-radio-group
v-else-if="item.type == 'radio'"
:disabled="item.disabled"
v-model="formModel[item.key]"
@change="item.changeEvent && item.changeEvent($event, item.key)"
>
<el-radio v-for="opt in item.options" :key="opt.value" :label="opt.value"
>{{ opt.label }}
</el-radio>
</el-radio-group>
<!-- 自定义项 -->
<template v-else-if="custom">
<slot name="item.customName"></slot>
</template>
</el-form-item>
</template>
</el-col>
</el-row>
</el-form>
</div>
</template>
JS部分
⚠️⚠️⚠️:这里主要接受一个下拉框数据,要求的是value和label,当后端返回的下拉数据不符合要求时,可以自己做一个map循环,处理一下数据。可以参考html部分中的下拉框部分的注视,有写明。
<script>
export default {
name: 'PublicForm',
props: {
// 表单的额外配置
formConfig: {
type: Object,
default: () => {
return {
labelWidth: '150px',
};
},
},
// form表单的所有字段
formModel: {
type: Object,
required: true,
},
// form表单中每个formItem的配置
formItemList: {
type: Array,
default: () => [],
},
},
computed: {},
watch: {
formItemList: {
handler(e) {
this.formItemList = e;
},
},
},
data() {
return {
// 默认不能选择今天之后的时间
pickerOptions: {
disabledDate(time) {
return time.getTime() > Date.now();
},
},
};
},
methods: {
// 需要提交和重置功能可以通过ref调用如下方法,或自行修改
submitForm() {
this.$refs['publicFormRef'].validate(valid => {
this.$emit('onSubmit', valid);
});
},
resetForm() {
this.$refs['publicFormRef'].resetFields();
this.$emit('onReset');
},
},
};
</script>
封装大部分是根据自己的需求来封装的,如果是基本的form表单,没有特别复杂的逻辑交互,完全可以C/V拿来用。
转载请标明出处,谢谢!
有很多不到位的地方,也有一些没表达清楚的部分,欢迎批评指正