封装的目的
在我们的日常开发中,尤其的后台管理系统,大量使用到element ui的表单组件,出于能少写一行代码绝不多写一个字母的程序猿来说,对常用的组件进行二次封装是非常必要的。
封装思路
- 可以动态生成表单控件
- 通过传入的参数进行父子组件之间的交互
- 代码可读性高
第一步
首先我们需要传入两个最重要的参数,第一个是与表单双向绑定的一个form,第二个是配置项参数,那么什么是配置项参数呢?这里指的是我们需要遍历一个数组里的对象,并拿到对象中的变量,并通过变量值来判断到底使用那些表单控件,上代码:
FormData: [
{
type: "Upload",
label: "封面",
prop: "cover",
placeholder: "请输入封面"
},
{
type: "Input",
label: "书名",
prop: "bookName",
placeholder: "请输入书名",
rules: [
{ required: true, message: "该选项不能为空", trigger: "blur" }
]
}
]
显而易见:
- type用来判断使用什么表单控件(这里使用的是upload、input框控件)
- label表示控件前的文本标识
- prop表示双向绑定的参数
- placeholder不多做解释
- rules为校验规则
参数进去了,组件肯定就要进行接收,所以,上代码:
props: {
isHandle: {
type: Boolean,
default: true
},
labelWidth: {
type: String,
default: "120px"
},
size: {
type: String,
default: "medium"
},
FormData: {
type: Array,
default: () => []
},
addForm: {
type: Object,
default: () => {}
},
searchHandle: {
type: Array,
default: () => []
}
},
父组件传入参数,子组件props接收,大家都知道的,不多做解释,这里对接收的参数做了一个类型限定,不太理解的可以去VUE官网找到相关api查看
下一步对配置项中的rules进行解析:
/** 解析表单的正则验证***/
rules() {
let rules = this.FormData.reduce((map, i) => {
if (i.rules) {
map[i.prop] = i.rules;
}
return map;
}, {});
return rules;
}
拿到配置项后,使用reduce进行遍历,并返回到rules中。
第二步
表单提交还需要按钮操作,那么如何将父组件的方法传入子组件呢? 这里使用了ref绑定dom元素,并使用$emit进行父子组件间传值,上代码:
子组件
// 验证表单
sublime() {
// 父组件的点击事件
this.$refs["FormData"].validate(valid => {
if (valid) {
this.$emit("sublime", valid);
} else {
return false;
}
});
},
// 重置表单
reset() {
this.$refs["FormData"].resetFields();
}
父组件:
//增加书籍提交表单方法
submitForm(valid) {
if (valid) {
dosomething.....
} else {
return false;
}
},
这样子父组件就能拿到子组件的校验规则返回参数。
在提交表单之前,先执行校验方法:
resetForm() {
this.$refs.FormData.reset();
this.$message.success("表单已重置");
},
// 提交操作
notify() {
this.$refs.FormData.sublime();
}
以上基本的思路就是这样
源代码
<template>
<div class="search_input">
<el-form
:addForm="addForm"
:FormData="FormData"
:size="size"
inline
:model="addForm"
:rules="rules"
ref="FormData"
:label-width="labelWidth"
>
<el-form-item v-for="item in FormData" :label="item.label" :key="item.prop" :prop="item.prop">
<!-- 输入框 -->
<el-input
v-if="item.type === 'Input'"
v-model="addForm[item.prop]"
:placeholder="item.placeholder"
></el-input>
<!-- 密码框 -->
<el-input
v-if="item.type === 'password'"
v-model="addForm[item.prop]"
:placeholder="item.placeholder"
auto-complete="off"
show-password
></el-input>
<!-- 滑块 -->
<el-slider v-if="item.type === 'Slider'" v-model="addForm[item.prop]"></el-slider>
<!-- 单选 -->
<el-radio-group v-if="item.type === 'Radio'" v-model="addForm[item.prop]">
<el-radio v-for="ra in item.radios" :label="ra.value" :key="ra.value">{{ ra.label }}</el-radio>
</el-radio-group>
<!-- 组合单选按钮 -->
<el-radio-group
v-if="item.type === 'RadioRadio'"
v-model="addForm[item.prop]"
@change="item.change && item.change(addForm[item.prop])"
>
<el-radio-button
v-for="ra in item.radios"
:label="ra.value"
:key="ra.value"
>{{ ra.label }}</el-radio-button>
</el-radio-group>
<!-- 复选框 -->
<el-checkbox-group v-if="item.type === 'Checkbox'" v-model="addForm[item.prop]">
<el-checkbox v-for="ch in item.checkboxs" :label="ch.value" :key="ch.value">{{ ch.label }}</el-checkbox>
</el-checkbox-group>
<!-- 日期 -->
<el-date-picker
v-if="item.type === 'Date'"
v-model="addForm[item.prop]"
value-format="yyyy-MM-dd"
@change="item.change(addForm[item.prop])"
:placeholder="item.placeholder"
></el-date-picker>
<!-- 时间 -->
<el-time-select v-if="item.type === 'Time'" v-model="addForm[item.prop]"></el-time-select>
<!-- 日期时间 -->
<el-date-picker
v-if="item.type === 'DateTime'"
type="datetime"
v-model="addForm[item.prop]"
:placeholder="item.placeholder"
value-format="yyyy-MM-dd hh:mm:ss"
:disabled="item.disable && item.disable(addForm[item.prop])"
@change="item.change(addForm[item.prop])"
></el-date-picker>
<!-- 起止时间 -->
<el-date-picker
v-if="item.type === 'Daterange'"
v-model="addForm[item.prop]"
type="daterange"
start-placeholder="开始日期"
end-placeholder="结束日期"
value-format="yyyy-MM-dd"
@change="item.change(addForm[item.prop])"
></el-date-picker>
<!-- 开关 -->
<el-switch v-if="item.type === 'Switch'" v-model="addForm[item.prop]"></el-switch>
<!-- 下拉框 -->
<!-- $forceUpdate() 下拉刷新,修复数据改变下拉框不变的bug -->
<el-select
v-if="item.type === 'Select'"
v-model="addForm[item.prop]"
@change="item.change(addForm[item.prop])"
@visible-change="$forceUpdate()"
>
<el-option
v-for="op in item.options"
:label="op.label"
:value="op.value"
:key="op.value"
>{{ op.label }}</el-option>
</el-select>
<!-- 上传文件 -->
<el-upload
v-if="item.type === 'Upload'"
v-model="addForm[item.prop]"
class="avatar-uploader"
action="https://jsonplaceholder.typicode.com/posts/"
:show-file-list="false"
>
<img v-if="item.imageUrl" :src="item.imageUrl" class="avatar" />
<i v-else class="el-icon-plus avatar-uploader-icon"></i>
</el-upload>
</el-form-item>
<el-form-item class="search_input_button" v-if="isHandle">
<el-button
v-for="item in searchHandle"
:key="item.label"
:type="item.type"
@click="item.handle()"
>
<span>{{ item.label }}</span>
</el-button>
</el-form-item>
</el-form>
</div>
</template>
<script>
export default {
props: {
isHandle: {
type: Boolean,
default: true
},
labelWidth: {
type: String,
default: "120px"
},
size: {
type: String,
default: "medium"
},
FormData: {
type: Array,
default: () => []
},
addForm: {
type: Object,
default: () => {}
},
searchHandle: {
type: Array,
default: () => []
}
},
computed: {
/** 解析表单的正则验证***/
rules() {
let rules = this.FormData.reduce((map, i) => {
if (i.rules) {
map[i.prop] = i.rules;
}
return map;
}, {});
return rules;
}
},
// mounted() {},
methods: {
// 验证表单
sublime() {
// 父组件的点击事件
this.$refs["FormData"].validate(valid => {
if (valid) {
this.$emit("sublime", valid);
} else {
return false;
}
});
},
// 重置表单
reset() {
this.$refs["FormData"].resetFields();
}
}
};
</script>
第一篇文章写的不好请大家多多担待。