子组件
<template>
<div class="formDiv">
<el-form
ref="form"
:model="form"
:inline="inline"
:rules="rules"
:label-width="labelWidth"
:class="{ flexForm: flex }"
>
<el-form-item
:label="item.title"
:prop="item.key"
v-for="item in options"
:key="item.key"
>
<div v-if="$slots[item.key]">
<slot :name="item.key"></slot>
</div>
<div v-else>
<el-input
:size="size"
v-model="form[item.key]"
v-if="item.type === 'text'"
:placeholder="
item.placeholder ? item.placeholder : '请输入' + item.title
"
:disabled="item.disabled"
clearable
></el-input>
<el-input
:size="size"
type="textarea"
:autosize="{ minRows: 3, maxRows: 6 }"
:placeholder="
item.placeholder ? item.placeholder : '请输入' + item.title
"
v-model="form[item.key]"
v-if="item.type === 'textarea'"
:disabled="item.disabled"
>
</el-input>
<el-input
v-if="item.type === 'password'"
type="password"
placeholder="请输入密码"
v-model="form[item.key]"
></el-input>
<el-switch
:size="size"
v-model="form[item.key]"
v-if="item.type === 'switch'"
active-color="#13ce66"
inactive-color="#ff4949"
:disabled="item.disabled"
>
</el-switch>
<el-time-picker
:size="size"
:placeholder="
item.placeholder ? item.placeholder : '请选择' + item.title
"
v-model="form[item.key]"
value-format="HH:mm:ss"
v-if="item.type === 'time'"
:disabled="item.disabled"
>
</el-time-picker>
<el-date-picker
type="date"
:placeholder="
item.placeholder ? item.placeholder : '请选择' + item.title
"
value-format="yyyy-MM-dd"
:size="size"
v-model="form[item.key]"
v-if="item.type === 'date'"
:disabled="item.disabled"
></el-date-picker>
<el-date-picker
type="datetime"
:placeholder="
item.placeholder ? item.placeholder : '请选择' + item.title
"
value-format="yyyy-MM-dd HH:mm:ss"
:size="size"
v-model="form[item.key]"
v-if="item.type === 'datetime'"
:disabled="item.disabled"
></el-date-picker>
<el-date-picker
type="daterange"
range-separator="至"
start-placeholder="开始日期"
end-placeholder="结束日期"
value-format="yyyy-MM-dd HH:mm:ss"
:size="size"
v-model="form[item.key]"
v-if="item.type === 'date-to-date'"
:disabled="item.disabled"
></el-date-picker>
<el-date-picker
type="datetimerange"
range-separator="至"
start-placeholder="开始日期"
end-placeholder="结束日期"
value-format="yyyy-MM-dd HH:mm:ss"
:size="size"
v-model="form[item.key]"
v-if="item.type === 'datetime-to-datetime'"
:disabled="item.disabled"
></el-date-picker>
<el-input-number
:size="size"
v-model="form[item.key]"
v-if="item.type === 'number'"
:disabled="item.disabled"
></el-input-number>
<el-select
:size="size"
v-model="form[item.key]"
v-if="item.type === 'select'"
clearable
:placeholder="
item.placeholder ? item.placeholder : '请选择' + item.title
"
:disabled="item.disabled"
>
<el-option
v-for="data in item.option.data"
:key="data[item.option.props.key]"
:label="data[item.option.props.label]"
:value="data[item.option.props.value]"
>
</el-option>
</el-select>
<el-cascader
:size="size"
v-model="form[item.key]"
v-if="item.type === 'cascader'"
:disabled="item.disabled"
:options="item.option.data"
@change="cascaderChange"
:props="item.option.props"
filterable
></el-cascader>
<el-radio-group
:size="size"
v-model="form[item.key]"
v-if="item.type === 'radio'"
:disabled="item.disabled"
>
<el-radio
v-for="data in item.option.data"
:key="data[item.option.props.key]"
:label="data[item.option.props.value]"
>{{ data[item.option.props.label] }}</el-radio
>
</el-radio-group>
<el-checkbox-group
:size="size"
v-model="form[item.key]"
v-if="item.type === 'checkbox'"
:disabled="item.disabled"
>
<el-checkbox
v-for="data in item.option.data"
:key="data[item.option.props.key]"
:label="data[item.option.props.label]"
>{{ data[item.option.props.label] }}</el-checkbox
>
</el-checkbox-group>
<el-upload
v-if="item.type === 'file'"
action="/api/upload_ajax"
:show-file-list="false"
:on-success="handleAvatarSuccess"
:disabled="item.disabled"
>
<img
v-if="form[item.key]"
:src="form[item.key]"
alt=""
style="width: 178px; height: 178px; border-radius: 6px"
@click="setFileKey(item.key)"
/>
<i
v-else
class="el-icon-plus avatar-uploader-icon"
@click="setFileKey(item.key)"
></i>
</el-upload>
</div>
</el-form-item>
<slot name="options"></slot>
</el-form>
</div>
</template>
<script>
export default {
name: "index",
props: {
// flex布局
flex: {
type: Boolean,
default: false,
},
// 表单
form: {
type: Object,
default: function () {
return {};
},
},
// 表单配置
options: {
type: Array,
default: function () {
return [];
},
},
// 表单验证规则
rules: {
type: Object,
default: function () {
return {};
},
},
// 是否行内表单
inline: {
type: Boolean,
default: function () {
return false;
},
},
// 表单表头宽度
labelWidth: {
type: String,
default: function () {
return "80px";
},
},
// 控件大小
size: {
type: String,
default: function () {
return "medium";
},
},
},
data() {
return {
fileKey: "",
};
},
mounted() {
// 动态添加验证
this.addRules(this.options);
// 初始化完成清除一下表单验证规则
this.$nextTick(function () {
this.clearValidate();
});
},
methods: {
cascaderChange(value) {
this.$emit("chooseGC", value);
},
/**
* @description: 动态添加表单验证
* @author: chenbz
* @date: 2021/4/27
*/
addRules(options) {
for (let i = 0; i < options.length; i++) {
// 判断是否需要添加验证
if (options[i].rules) {
// 判断用户是否已经自定义验证了
if (!this.rules[options[i].key]) {
// 动态生成验证方法
let data = [
{
required: true,
message: "",
trigger: "",
},
];
// 动态添加验证方式:失去焦点触发/确认时触发
if (options[i].type === ("input" || "text")) {
data[0].message = "请输入" + options[i].title;
data[0].trigger = "blur";
} else {
data[0].message = "请选择" + options[i].title;
data[0].trigger = "change";
}
// 触发vue更新
this.$set(this.rules, options[i].key, data);
}
}
}
},
/**
* @description: 表单验证
* @author: chenbz
* @date: 2021/5/10
*/
validate() {
let isValidate = false;
this.$refs.form.validate((valid) => {
if (valid) {
isValidate = true;
console.log("表单提交", this.form);
}
});
return isValidate;
},
/**
* @description: 清除表单验证
* @author: chenbz
* @date: 2021/5/18
*/
clearValidate() {
this.$refs.form.clearValidate();
},
setFileKey(key) {
// console.log(key);
this.fileKey = key;
},
handleAvatarSuccess(res, file) {
// console.log(res);
// console.log(file);
file;
this.form[this.fileKey] = res.data;
},
},
};
</script>
<style lang="less">
.formDiv {
.flexForm {
width: 100%;
display: flex;
justify-content: space-between;
flex-wrap: wrap;
.el-form-item {
flex: 0 0 45% !important;
}
}
}
</style>
父组件
直接在父组件中如今并传入对应的数据就好,例如
formData: {
flex: false, //开启flex布局
form: {
sex: "",
name: "",
account: "", //账号
password: "", //密码
gradeClass: "",
},
options: [
{
title: "名字",
key: "name",
type: "text",
// rules: true,
},
{
title: "账号",
key: "account",
type: "text",
// rules: true,
},
{
title: "密码",
key: "password",
type: "password",
// rules: true,
},
{
title: "年级/班级",
key: "gradeClass",
type: "cascader",
option: {
data: [],
props: {
value: "id", // 指定value对应data的字段
},
},
// rules: true,
},
],
rules: {},
},