使用vue+elementui实现自定义表单,支持插槽及原生拓展
表单通常用来当做查询或提交内容,代码如下:
1.表单查询
<template>
<div class="default-form">
<el-form
ref="formData"
:model="formData"
:label-width="labelWidth"
size="mini"
>
<el-row>
<el-col
:span="defaultColSpan"
v-for="item in formItems"
:key="item.prop"
>
<el-form-item
:label="item.defaultLabel ? item.defaultLabel : $t(item.label)"
:prop="item.prop"
v-if="
!item.isHide &&
(!item.companyType || item.companyType == companyType)
"
>
<template v-if="item.type === 'input'">
<el-input
v-model="formData[`${item.prop}`]"
v-bind="item.options"
clearable
:placeholder="$t(item.placeholder)"
@change="selectChange($event, item)"
size="small"
></el-input>
</template>
<template v-if="item.type === 'datepicker'">
<el-date-picker
v-model="formData[`${item.prop}`]"
v-bind="item.options"
type="daterange"
@change="handleChangeDatePicker($event, item)"
format="yyyy-MM-dd"
value-format="yyyy/MM/dd HH:mm:ss"
size="small"
:start-placeholder="$t(item.options.startPlaceholder)"
:end-placeholder="$t(item.options.endPlaceholder)"
>
</el-date-picker>
</template>
<template v-if="item.type === 'date'">
<el-date-picker
v-model="formData[`${item.prop}`]"
v-bind="item.options"
@change="handleChangeDatePicker($event, item)"
format="yyyy-MM-dd"
value-format="yyyy/MM/dd HH:mm:ss"
size="small"
>
</el-date-picker>
</template>
<template v-if="item.type === 'select'">
<el-select
v-model="formData[`${item.prop}`]"
v-bind="item.options"
filterable
:multiple="item.multiple"
no-data-text="No Data"
clearable
:placeholder="$t(item.placeholder)"
@change="selectChange($event, item)"
size="small"
>
<el-option
v-for="selectItem in item.selectLists"
:value="selectItem.value"
:label="
selectItem.defaultLabel
? selectItem.defaultLabel
: $t(selectItem.label)
"
:key="selectItem.value"
></el-option>
</el-select>
</template>
<template v-if="item.type === 'cascader'">
<el-cascader
v-model="formData[`${item.prop}`]"
v-bind="item.options"
:props="item.props"
:options="item.cascaderOptions"
clearable
:placeholder="$t(item.placeholder)"
@change="selectChange($event, item)"
size="small"
></el-cascader>
</template>
<template v-if="item.type === 'slot'">
<slot :name="item.slotName"></slot>
</template>
</el-form-item>
</el-col>
<el-col
:span="btnColSpan"
style="display: flex; justify-content: flex-end"
>
<e-button
class="search"
type="ghost"
icon="search"
@click="handleSearch"
>
{{ $t("platform.orderplacement.search") }}
</e-button>
<e-button
htmlType="reset"
icon="eraser"
@click="handleReset('formData')"
>
{{ $t("platform.orderplacement.clear") }}
</e-button>
<div></div>
<Icon
:type="collapseIcon"
class="red"
style="line-height: 30px; margin: 0 6px; cursor: pointer"
@click="hanldeCollapse"
></Icon>
</el-col>
</el-row>
</el-form>
</div>
</template>
<script>
export default {
props: {
labelWidth: {
type: String,
default: "121px",
},
//表单字段
formItems: {
type: Array,
default: () => {},
},
defaultColSpan: {
type: Number,
default: 6,
},
loginedUserinfo: {
type: Object,
default: () => {},
},
//分页信息
pageInfo: {
type: Object,
default: () => ({
pageSize: 10,
pageNum: 1,
}),
},
//是否包括card
isCard: {
type: Boolean,
default: true,
},
//下拉框衍生出的key value
addFormData: {
type: Object,
default: () => {},
},
//size
size: {
type: String,
default: "small",
},
},
data() {
return {
btnColSpan: 12, //按钮组显示最右边
defaultBtnColSpan: 12, //保留默认值 用作折叠操作后
isCollapse: true, //默认展开
collapseIcon: "angle-double-down", //默认展开的icon
initFormData: {}, //初始化表单对象
formData: {}, //提交时的表单对象
language: "en_US", //语言
colSpanProportion: {
6: [24, 18, 12, 6],
8: [24, 16, 8],
12: [24, 12],
24: [24],
},
isUpdateForm: false, //判断是否修改form表单内容
};
},
methods: {
//处理时间戳
handleChangeDatePicker(value, item) {
this.isUpdateForm = true;
if (value === null) {
this.formData[item.startTime] = null;
this.formData[item.endTime] = null;
return;
}
this.formData[`${item.startTime}`] = new Date(value[0]).getTime();
this.formData[`${item.endTime}`] = new Date(value[1]).getTime();
console.log(this.formData, "修改日期后的formData");
},
//展开按钮
hanldeCollapse() {
this.isCollapse = !this.isCollapse;
this.collapseIcon = this.isCollapse
? "angle-double-down"
: "angle-double-up";
let formItem = this.formItems.filter(
(i) => !i.companyType || i.companyType == this.companyType
);
let formItemLength = formItem.length;
//折叠 当colspan为 6 formItem大于8时 隐藏formItem.length - 8 8=24/colspan *2
let currentColSpan = (24 / this.defaultColSpan) * 2;
let arr = this.colSpanProportion[this.defaultColSpan];
this.btnColSpan = arr[formItemLength % (24 / this.defaultColSpan)];
if (this.formItems.length < 8) {
return;
}
if (this.isCollapse) {
this.btnColSpan = 24;
let formItems = this.formItems;
let arr = formItems.slice(currentColSpan, formItemLength);
console.log(arr);
this.formItems.forEach((i, index) => {
arr.forEach((k) => {
if (i.prop === k.prop) {
i.isHide = true;
}
});
});
} else {
this.formItems.forEach((i, index) => {
i.isHide = false;
});
let arr = this.colSpanProportion[this.defaultColSpan];
this.defaultColSpan = 6;
}
},
//表单查询
handleSearch() {
let params = {
pageSize: this.pageInfo.pageSize,
pageNum: this.pageInfo.pageNum,
language: this.language,
companyType: this.companyType,
username: this.loginedUserinfo.username,
companyCode: this.loginedUserinfo.companyCode,
};
params = { ...params, ...this.formData, ...this.addFormData };
console.log(params, "查询对象");
// this.$parent.getList(params);
this.$emit("searchData", params, this.isUpdateForm);
this.isUpdateForm = false;
},
//清空表单
handleReset(formName) {
this.$refs[formName].resetFields();
//删除日期 item中的startTime endTime
for (let i in this.formItems) {
if (this.formItems[i]?.startTime || this.formItems[i]?.endTime) {
this.formData[`${this.formItems[i]?.startTime}`] = null;
this.formData[`${this.formItems[i]?.endTime}`] = null;
}
//清空数组
if (Array.isArray(this.formItems[i].prop)) {
this.formItems[i].prop = [];
}
this.formData.poStatusList = []
this.formData.shipTypeList = []
this.formData.categoryList = []
}
this.pageInfo.pageSize = 10;
this.pageInfo.pageNum = 1;
let params = {
pageSize: this.pageInfo.pageSize,
pageNum: this.pageInfo.pageNum,
language: this.language,
companyType: this.companyType,
username: this.loginedUserinfo.username,
companyCode: this.loginedUserinfo.companyCode,
};
params = { ...params, ...this.formData, ...this.addFormData };
console.log(params, "清空后的查询对象");
this.$emit("searchData", params);
},
//下拉框字典值
selectChange(val, item) {
console.log(val, item.prop, item);
//保存级联的原数据
if (item.type === "cascader") {
this.formData[`${item.prop}_cascader`] = val;
}
this.isUpdateForm = true;
this.$emit("selectChange", val, item.prop);
},
},
created() {
//获取companyType
this.companyType = this.loginedUserinfo.companyType;
//获取语言
this.language = localStorage.getItem("appLang") || "en_US";
//初始化表单对象
for (let i of this.formItems) {
//日期为[]
let exceptType = ["datepicker"];
this.initFormData[`${i.prop}`] = exceptType.includes(i.type) ? [] : null;
}
this.formData = { ...this.initFormData };
//让按钮始终在最右边展示
//判断表格部分字段当companyType等于1 才展示,否则不展示
let formItem = this.formItems.filter(
(i) => !i.companyType || i.companyType == this.companyType
);
let formItemLength = formItem.length;
console.log(formItem, "formItem");
// let arr = [24, 18, 12, 6];
let arr = this.colSpanProportion[`${this.defaultColSpan}`];
//求余数 4-余数
console.log(arr, this.btnColSpan);
if (formItem.length > 8) {
formItem.forEach((i, index) => {
i.isHide = index > 7 ? true : false;
});
this.btnColSpan = 24;
} else {
let arrLength = arr.length;
this.btnColSpan = arr[formItem.length % arrLength];
// arr[formItemLength % (24 / this.defaultBtnColSpan)];
}
// this.defaultBtnColSpan = this.btnColSpan;
console.log(this.initFormData, "初始化表单对象");
console.log(this.formData, "初始化formData");
},
};
</script>
<style scoped lang="scss">
.list {
margin-top: 20px;
border-bottom: 2px solid #efefef;
}
.search ::v-deep .put-btn {
background: #79003d;
color: #fff;
}
.red {
color: #79003d;
}
.content {
width: 87%;
margin: 30px auto;
}
.title {
font-size: 16px;
font-weight: bold;
color: rgb(0, 0, 0);
border-left: #000 solid 4px;
padding-left: 5px;
}
.item {
margin-top: 20px;
}
::v-deep .cell .el-date-editor.el-input {
width: 135px;
}
.content ::v-deep .put-row {
display: flex;
justify-content: space-between;
}
.red ::v-deep i.fa {
color: #79003d;
}
.btnTips {
border-radius: 5px;
}
::v-deep .el-dialog__footer {
text-align: center;
}
::v-deep .checkbox .el-checkbox__inner {
display: none;
}
::v-deep .el-form-item__content .el-input__inner {
padding: 0 7px;
}
::v-deep .exportSelect .el-input__inner {
padding: 0 7px;
}
::v-deep .el-form-item__content .el-date-editor {
width: 100%;
}
::v-deep .el-textarea__inner {
padding: 0 7px;
}
::v-deep .el-input__inner[disabled] {
color: #495060;
}
::v-deep .el-form-item__label {
font-size: 12px;
}
::v-deep .put-input {
font-size: 12px;
}
::v-deep .el-checkbox__label {
font-size: 12px; //.put-btn
}
::v-deep .put-btn {
font-size: 12px;
}
.flex ::v-deep .el-form-item__content {
display: flex;
}
::v-deep .el-drawer__body {
padding: 0 20px 0 20px;
}
.black > span {
margin: 0 5px;
}
::v-deep input::-webkit-input-placeholder {
/* placeholder字体大小 */
font-size: 12px;
}
::v-deep .el-range-editor--small .el-range-separator {
line-height: 30px;
}
::v-deep .el-range-editor--small .el-range__icon {
line-height: 32px;
}
::v-deep .el-drawer__header {
font-size: 14px;
color: #1c2438;
}
.card2 ::v-deep .put-card-body {
padding: 10px 5%;
}
::v-deep .allocationNo .cell {
display: flex;
display: -webkit-flex;
align-items: center;
}
.el-select,
.el-cascader {
width: 100%;
}
::v-deep .el-select__tags {
flex-wrap: nowrap;
overflow: hidden;
}
::v-deep .el-cascader__tags {
flex-wrap: nowrap;
overflow: hidden;
}
</style>
2.表单提交
<el-form :model="formData" ref="formData" size="medium" label-suffix=":">
<el-row>
<el-col
v-for="formItem in FomrItemList"
:key="formItem.prop"
:span="formItem.colSpan ? formItem.colSpan : formItem.defaultColSpan"
>
<!--title-->
<template v-if="formItem.title">
<p class="p-title">
{{ formItem.label ? $t(formItem.label) : formItem.defaultLabel }}
</p>
</template>
<!--表单内容-->
<template v-else>
<el-form-item
:label="
formItem.label ? $t(formItem.label) : formItem.defaultLabel
"
:prop="formItem.prop"
:rules="formItem.rules"
:class="formItem.className"
:label-width="formItem.labelWidth ? formItem.labelWidth : '250px'"
>
<template v-if="formItem.type === 'input'">
<el-input
v-model="formData[`${formItem.prop}`]"
:placeholder="formItem.placeholder"
:clearable="formItem.clearable"
@change="handleChange($event, formItem)"
:disabled="formItem.disabled"
v-bind="formItem.options"
></el-input>
</template>
<template v-if="formItem.type === 'textarea'">
<el-input
type="textarea"
v-model="formData[`${formItem.prop}`]"
:placeholder="formItem.placeholder"
:clearable="formItem.clearable"
@change="handleChange($event, formItem)"
:disabled="formItem.disabled"
v-bind="formItem.options"
></el-input>
</template>
<template v-if="formItem.type === 'select'">
<el-select
v-model="formData[`${formItem.prop}`]"
:placeholder="formItem.placeholder"
:clearable="formItem.clearable"
:disabled="formItem.disabled"
@change="handleChange($event, formItem)"
v-bind="formItem.options"
>
<el-option
v-for="selectItem in formItem.selectList"
:key="selectItem.key"
:label="selectItem.label"
:value="selectItem.key"
>
</el-option>
</el-select>
</template>
<template v-if="formItem.type === 'date'">
<el-date-picker
type="date"
:placeholder="formItem.placeholder"
v-model="formData[`${formItem.prop}`]"
style="width: 100%"
:clearable="formItem.clearable"
:disabled="formItem.disabled"
v-bind="formItem.options"
@change="handleChange($event, formItem)"
></el-date-picker>
</template>
<template v-if="formItem.slotName">
<slot
:name="formItem.slotName"
>
</slot>
</template>
</el-form-item>
</template>
</el-col>
</el-row>
</el-form>
//使用
FomrItemList = [
{
label: "", //名称
defaultLabel: "Buyer company", //默认名称
prop: "a", //对应字段
colSpan: "", //栅格化布局
defaultColSpan: 24, //默认栅格化布局
rules: [], //校验规则
method: "handleChange", //方法名
type: "input", //组件类型 input/select/date/textarea
selectList: [], //当type=select 下拉列表
slotName: "", //插槽
placeholder: "", //placeholder
clearable: false, //是否显示清除按钮
disabled: true, //是否禁用
},
]