封装 myform 组件

<template>
  <div class="myform">

    <el-form
      v-bind="$attrs"
      v-on="$listeners"
      :model="formmodel"
      :inline="inline"
      ref="myform"
      :rules="rules"
      :label-width="$attrs['label-width']||calclabelwidth"
    >
      <div style="width:100%">
        <slot name="btns" :data="Object.assign({},formmodel)"></slot>
      </div>
      <el-form-item
        :label="item.label+':'"
        :prop="item.prop"
        v-for="(item, index) in formconfig"
        :style="{width: item.width +'%','margin-right':0}"
        :key="index"
      >
        <!--自定义render-->
        <template v-if="item.render">
          <component
            :is="'renderComponent'"
            :value="formmodel[item.prop]"
            :input="e => formmodel[item.prop] = e"
            v-bind="{ ...item }"
          ></component>
        </template>
        <!--自定义插槽-->
        <template v-else-if="item.type==='custom'">
          <slot :name="item.slot" :row="{ ...item, formmodel, index }" />
        </template>

        <!--下拉框-->
        <template v-else-if="item.type === 'select'">
          <el-select v-bind="item.attrs" v-model="formmodel[item.prop]" v-on="getlisteners(item)">
             <el-option
              v-for="(sitem, index) in getOptions(item)"
              :key="index"
              :label="sitem[item.optionlabel||'text']"
              :value="sitem[item.optionvalue||'value']"
            ></el-option>
          </el-select>
        </template>
        <!--component-->
        <template v-else-if="item.type">
          <myitem v-bind="getattrs(item)" v-on="getlisteners(item)" v-model="formmodel[item.prop]"></myitem>
        </template>
      </el-form-item>
      <div style="width:100%">
        <slot name="bottom" :data="Object.assign({},formmodel)"></slot>
      </div>
    </el-form>
  </div>
</template>

<script>
// 邮箱的正则校验
const validateEmail = (rule, value, callback) => {
  if (value) {
    var email =
      /^([a-zA-Z0-9]+[_|\_|\.]?)*[a-zA-Z0-9]+@([a-zA-Z0-9]+[_|\_|\.]?)*[a-zA-Z0-9]+\.[a-zA-Z]{2,3}$/;
    if (!email.test(value)) {
      callback(new Error("邮箱地址格式不正确"));
    } else {
      callback();
    }
  } else {
    //可以为空
    callback();
  }
};

// url地址的正则校验
const validateUrl = (rule, value, callback) => {
  if (value != "") {
    var Url =
      /^((ht|f)tps?):\/\/([\w-]+(\.[\w-]+)*\/?)+(\?([\w\-\.,@?^=%&:\/~\+#]*)+)?$/;
    if (!Url.test(value)) {
      callback(new Error("URL地址格式不正确"));
    } else {
      callback();
    }
  }
};

// 电话号码的正则校验
const validateTel = (rule, value, callback) => {
  if (value != "") {
    var tel = /^1[3456789]\d{9}$/;
    if (!tel.test(value)) {
      callback(new Error("电话号码格式不正确"));
    } else {
      callback();
    }
  }
};

// 身份证号码的校验规则
const validateIdCard = (rule, value, callback) => {
  if (value != "") {
    var IdCard =
      /(^[1-9]\d{5}(18|19|([23]\d))\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$)|(^[1-9]\d{7}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{3}$)/;
    if (!IdCard.test(value)) {
      callback(new Error("身份证号码格式不正确"));
    } else {
      callback();
    }
  }
};

// 日期校验规则
const validateDate = (rule, value, callback) => {
  if (value != "") {
    var Date =
      /^(\d{4})[-\/](\d{1}|0\d{1}|1[0-2])([-\/](\d{1}|0\d{1}|[1-2][0-9]|3[0-1]))*$/;
    if (!Date.test(value)) {
      callback(new Error("日期格式不正确"));
    } else {
      callback();
    }
  }
};

// 数字校验
const validateNum = (rule, value, callback) => {
  if (!value || isNaN(value)) {
    callback(new Error("数字格式不正确"));
  } else {
    callback();
  }
};

// 时间校验规则
const validateTime = (rule, value, callback) => {
  if (value != null && value != "") {
    var flag = /^([0-1][0-9]|2[0-3]):([0-5][0-9])$/;
    if (!flag.test(value)) {
      callback(new Error("时间格式不正确,格式为  HH:MM"));
    } else {
      callback();
    }
  }
};

// 自定义校验规则
const validateCustom = (val) => {
  return (rule, value, callback) => {
    if (value != null && value != "") {
      var flag = new RegExp(val.patternStr);
      if (!flag.test(value)) {
        callback(new Error(String(val.errorMessage)));
      } else {
        callback();
      }
    }
  };
};

// 长度校验
const min = (val) => {
  return (rule, value, callback) => {
    if (value != null && value != "") {
      if (val.min && val.min > value.length) {
        callback(new Error(`长度下限为 ${val.min} 个字符`));
      } else {
        callback();
      }
    } else {
      callback(new Error(`长度下限为 ${val.min} 个字符`));
    }
  };
};

const max = (val) => {
  return (rule, value, callback) => {
    if (value != null && value != "") {
      if (val.max && val.max < value.length) {
        callback(new Error(`长度上限为 ${val.max} 个字符`));
      } else {
        callback();
      }
    } else {
      callback(new Error(`长度上限为 ${val.max} 个字符`));
    }
  };
};

const regExpFn = {
  email: validateEmail,
  url: validateUrl,
  phone: validateTel,
  identity: validateIdCard,
  date: validateDate,
  number: validateNum,
  timeEmptyAble: validateTime,
  validateCustom: validateCustom,
  min: min,
  max: max,
};

const renderComponent = {
  functional: true,
  props: ["value"],
  render(h, ctx) {
    const { render, attrs, input: handleInput } = ctx.data.attrs;
    return render(h, {
      attrs: {
        ...attrs,
        value: ctx.props.value,
      },
      on: {
        input(e) {
          // handleInput(e);
        },
      },
    });
  },
};
export default {
  inheritAttrs: false,
  name: "myform",
  components: { renderComponent },
  props: {
    selectUpdate: {
      type: Object,
      default: () => ({}),
    },
    inline: {
      type: Boolean,
      default: true,
    },
    formmodel: {
      type: Object,
      default: () => ({}),
    },
    formconfig: {
      type: Array,
      default: () => [],
    },
  },
  data() {
    return {
      rules: {},
    };
  },
  watch: {
    formconfig: {
      handler(val) {
        this.generateRules();
      },
    },
  },
  computed: {
    calclabelwidth() {
      let width = 100;
      let len = 2;
      if (Array.isArray(this.formconfig) && this.formconfig.length) {
        let lenlist = this.formconfig.map((item) => {
          if (typeof item.label === "string") {
            return item.label.length;
          } else {
            return 2;
          }
        });
        len = Math.max.apply(null, lenlist);
      }

      width =
        parseFloat(len * 16 + 30) > parseFloat(width) ? len * 16 + 30 : width;
      return width + "px";
    },
  },
  methods: {
     getOptions(item){

        if(item.optkey){
         return this.selectUpdate[item.optkey]
        }else{
return this.selectUpdate[item.prop]||item.options||[]
        }

    },
    //设置下拉
    setOptions() {
      Object.keys(this.selectUpdate).forEach((v) => {
        const index = this.formconfig.findIndex((k) => k.prop === v);
        if (index !== -1) {
          this.$set(this.formconfig[index], "options", this.selectUpdate[v]);
        }
        const index2 = this.formconfig.findIndex((k) => k.optkey === v);
        if (index2 !== -1) {
          this.$set(this.formconfig[index2], "options", this.selectUpdate[v]);
        }
      });
    },
    // 查询系统集成的自定规则
    ergExtFunc(val) {
      if (regExpFn[val]) {
        return {
          trigger: "blur",
          validator: regExpFn[val],
        };
      }
    },

    // 根据传进来的正则规则生成符合el-form的校验规则
    regExpCustom(val) {
      // console.log(val);
      // if (val.patternStr && val.errorMessage) return;
      if (val.type == "select" || val.type == "tree") {
        return {
          trigger: "change",
          validator: regExpFn.validateCustom(val),
        };
      }
      // console.log(regExpFn.validateCustom(val));
      return {
        trigger: "blur",
        validator: regExpFn.validateCustom(val),
      };
    },

    generateRules() {
      // 生成校验规则
      this.rules = {};
      this.formconfig.forEach((v) => {
        const model = [];
        const item = {};
        const origin = {};
        // 必填校验
        if (v.required) {
          if (v.type == "select" || v.type == "tree") {
            item.required = true;
            item.message = v.message || `${v.label}必填`;
            item.trigger = "change";
            model.push(item);
          } else if (v.type == "selectInput") {
            model.push({
              required: true,
              message: `${v.label}必填`,
              trigger: "change",
            });
          } else {
            item.required = true;
            item.message = v.message || `${v.label}必填`;
            item.trigger = "blur";
            model.push(item);
          }
        }

        // 长度校验
        if (v.min || v.max) {
          if (v.min) {
            item.min = v.min;
            item.message = `长度下限 ${item.min} 个字符`;
          }
          if (v.max) {
            item.max = v.max;
            item.message = `长度上限 ${item.max} 个字符`;
          }
          if (v.min && v.max) {
            item.message = `长度在 ${item.min} 到 ${item.max} 个字符`;
          }
          item.trigger = "blur";
          model.push(item);
        }

        if (typeof v.validate == "string") {
          const validateList = v.validate.split("|");
          // console.log(validateList);
          validateList.forEach((validate) => {
            // 以下皆为系统自定义集成的规则
            if (validate == "date") {
              model.push(this.ergExtFunc("date"));
            }
            if (validate == "email") {
              model.push(this.ergExtFunc("email"));
            }
            if (validate == "url") {
              model.push(this.ergExtFunc("url"));
            }
            if (validate == "phone") {
              model.push(this.ergExtFunc("phone"));
            }
            if (validate == "identity") {
              model.push(this.ergExtFunc("identity"));
            }
            if (validate == "number") {
              model.push(this.ergExtFunc("number"));
            }
            if (validate == "timeEmptyAble") {
              model.push(this.ergExtFunc("timeEmptyAble"));
            }
            // 以下为用户添加的自定义校验规则
            if (validate == "pattern") {
              model.push(this.regExpCustom(v));
            }
          });
        }

        // 自定义校验规则
        if (v.validate && typeof v.validate != "string") {
          if (v.type == "select" || v.type == "tree") {
            origin.trigger = "change";
            origin.validator = v.validate;
            model.push(origin);
          } else {
            origin.trigger = "blur";
            origin.validator = v.validate;
            model.push(origin);
          }
        }
        if (model.length > 0) {
          this.$set(this.rules, v.prop, model);
        }

        if (v.type === "selectDate") {
          v.children.forEach((j) => {
            if (j.required) {
              item.required = true;
              item.message = `${v.label}必填`;
              item.trigger = "change";
              model.unshift(item);
              this.$set(this.rules, j.prop, model);
            }
          });
        }
      });
       this.$nextTick(() => {
        this.$refs.myform.clearValidate();
      });
    },
    //继承el-form 方法
    extendMethod() {
      const refMethod = Object.entries(this.$refs["myform"]);
      for (const [key, value] of refMethod) {
        if (!(key.includes("$") || key.includes("_"))) {
          this[key] = value;
        }
      }
    },

    getattrs(item) {
      let obj = item.attrs || {};
      if (!obj.placeholder) {
        let prevtext = "请输入";
        if (item.type === "select") {
          prevtext = "请选择";
        }
        obj.placeholder = prevtext + item.label;
      }
      if (typeof item.disabled === "boolean") {
        obj.disabled = item.disabled;
      }
      let component = "";
      switch (item.type) {
        case "input":
        case "search":
        case "text":
          component = "el-input";
          break;
        case "textarea":
          component = "el-input";
          obj.type = "textarea";
          obj.rows = parseInt(obj.rows) || 3;
          obj.resize = "none";
          break;
        case "switch":
          component = "el-switch";
          obj.activeColor = obj.activeColor || "rgb(64,158,255)";
          obj.inactiveColor = obj.inactiveColor || "#ff4949";
          break;
        case "date":
          component = "el-date-picker";
          obj.type = "date";
          obj.format = "yyyy-MM-dd";
          obj.valueFormat = "yyyy-MM-dd";
          break;
        case "year":
          component = "el-date-picker";
          obj.type = "year";
          obj.format = "yyyy";
          obj.valueFormat = "yyyy";
          break;
        case "yearmonth":
          component = "el-date-picker";

          obj.type = "month";
          obj.format = "yyyy-MM";
          obj.valueFormat = "yyyy-MM";
          break;
        case "datetimerange":
          component = "el-date-picker";
          obj.type = "datetimerange";
          obj.rangeSeparator = "至";
          obj.format = "yyyy-MM-dd";
          obj.valueFormat = "yyyy-MM-dd";

          break;

        default:
          component;
          break;
      }

      if (!obj.component) {
        obj.component = component;
      }
      return obj;
    },
    getlisteners(item) {
      return item.event || {};
    },
  },
  mounted() {
    this.extendMethod();
      // this.setOptions();
  },
  created() {
    this.generateRules();
    //  this.$emit('update:model', this.model);
  },
};
</script>
<style lang="scss" scoped>
.myform {
}
</style>
<myform :selectUpdate="selectUpdate"  :formconfig="formconfig" :formmodel="formmodel" @search='search'></myform>
search(val,type){
      console.log(val,type);
    }
formmodel: {
        // date: "",
        // name: "",
        // address: "",
        // number: "",
        // scholl: "",
      },
      formconfig: [
         {
          type: "text",

          prop: "date",
          label: "日期",
          width: 50,
          event: {
            change: (a, b, c, d) => {
              console.log(a, b, c, d);
            },
          },
        },
         {
          type: "text",

          prop: "date",
          label: "日期",
          width: 50,
          event: {
            change: (a, b, c, d) => {
              console.log(a, b, c, d);
            },
          },
        },
         {
          type: "text",

          prop: "date",
          label: "日期",
          width: 50,
          event: {
            change: (a, b, c, d) => {
              console.log(a, b, c, d);
            },
          },
        },
        {
          type: "text",

          prop: "date",
          label: "日期",
          width: 50,
          event: {
            change: (a, b, c, d) => {
              console.log(a, b, c, d);
            },
          },
        },
        {
          type: "text",
          prop: "name",
          label: "名称",

          width: 50,
          attrs: {
            placeholder: "请填写名称",
          },
        },
        {
          type: "select",
          prop: "address",
          label: "地址",
          width: 50,
          attrs: {
            placeholder: "请选择地址",
            style: {
              width: "100%",
            },
          },
          optionlabel: "11",
          optionvalue: "777",

          // options: {
          //   // data: this.tableData,
          //   // extraProps: {
          //   //   value: "address",
          //   //   label: "address",
          //   // },
          // },
        },
        {
          type: "text",
          slot: "number",
          width: 50,
          label: "编号",
          attrs: {
            placeholder: "请输入编号",
          },
        },
        {
          type: "text",
          prop: "scholl",
          width: 50,
          label: "毕业学校",
          attrs: {
            placeholder: "请输入毕业学校",
          },
          // render: (h, props) =>
          //   h("el-input", {
          //     ...props,
          //   }),
        },
      ],
posted @ 2023-07-09 15:27  7c89  阅读(10)  评论(0编辑  收藏  举报