Bootstrap

使用vue+elementui实现自定义表单,支持插槽及原生拓展

使用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, //是否禁用
	},
]


;