飞道的博客

封装 element-ui 的 Form表单

456人阅读  评论(0)

# 新建 Form.vue

src/components/Form.vue

<template>
  <div>
    <el-form
      ref="form"
      :model="form"
      :inline="inline"
      :rules="rules"
      :label-width="labelWidth"
      class="form"
    >
      <el-form-item
        :label="item.title"
        :prop="item.key"
        v-for="item in options"
        :key="item.key"
      >
        <el-input
          :size="size"
          v-model="form[item.key]"
          v-if="item.type === 'input'"
          :placeholder="'请输入' + item.title"
          clearable
        ></el-input>
        <el-input
          :size="size"
          type="textarea"
          :autosize="{ minRows: 3, maxRows: 6 }"
          :placeholder="'请输入' + item.title"
          v-model="form[item.key]"
          v-if="item.type === 'text'"
        >
        </el-input>
        <el-switch
          :size="size"
          v-model="form[item.key]"
          v-if="item.type === 'switch'"
          active-color="#13ce66"
          inactive-color="#ff4949"
        >
        </el-switch>
        <el-time-picker
          :size="size"
          :placeholder="'请选择' + item.title"
          v-model="form[item.key]"
          value-format="HH:mm:ss"
          v-if="item.type === 'time'"
        >
        </el-time-picker>
        <el-date-picker
          type="date"
          :placeholder="'请选择' + item.title"
          value-format="yyyy-MM-dd"
          :size="size"
          v-model="form[item.key]"
          v-if="item.type === 'date'"
        ></el-date-picker>
        <el-date-picker
          type="datetime"
          :placeholder="'请选择' + item.title"
          value-format="yyyy-MM-dd HH:mm:ss"
          :size="size"
          v-model="form[item.key]"
          v-if="item.type === 'datetime'"
        ></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'"
        ></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'"
        ></el-date-picker>
        <el-input-number
          :size="size"
          v-model="form[item.key]"
          v-if="item.type === 'number'"
        ></el-input-number>
        <el-select
          :size="size"
          v-model="form[item.key]"
          v-if="item.type === 'select'"
          clearable
          :placeholder="'请选择' + item.title"
        >
          <el-option
            v-for="data in item.option.data"
            :key="data[item.option.key]"
            :label="data[item.option.label]"
            :value="data[item.option.value]"
          >
          </el-option>
        </el-select>
        <el-radio-group
          :size="size"
          v-model="form[item.key]"
          v-if="item.type === 'radio'"
        >
          <el-radio
            v-for="data in item.option.data"
            :key="data[item.option.key]"
            :label="data[item.option.value]"
            >{
  { data[item.option.label] }}</el-radio
          >
        </el-radio-group>
        <el-checkbox-group
          :size="size"
          v-model="form[item.key]"
          v-if="item.type === 'checkbox'"
        >
          <el-checkbox
            v-for="data in item.option.data"
            :key="data[item.option.key]"
            :label="data[item.option.value]"
            >{
  { data[item.option.label] }}</el-checkbox
          >
        </el-checkbox-group>
      </el-form-item>
      <slot name="file"></slot>
      <el-form-item v-if="search">
        <el-button type="primary" :size="size" @click="onSearch">
          {
  { searchText }}
        </el-button>
      </el-form-item>
    </el-form>
  </div>
</template>

<script>
export default {
  name: "index",
  props: {
    // 表单
    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;
      }
    },
    // 是否开启搜索
    search: {
      type: Boolean,
      default: function() {
        return false;
      }
    },
    // 搜索按钮的文字
    searchText: {
      type: String,
      default: function() {
        return "查询";
      }
    },
    // 表单表头宽度
    labelWidth: {
      type: String,
      default: function() {
        return "80px";
      }
    },
    // 控件大小
    size: {
      type: String,
      default: function() {
        return "medium";
      }
    }
  },
  data() {
    return {};
  },
  mounted() {
    // 动态添加验证
    this.addRules(this.options);
    // 初始化完成清除一下表单验证规则
    this.$nextTick(function() {
      this.$refs.form.clearValidate();
    });
  },
  methods: {
    /**
     * @description: 点击了搜索
     * @author: chenbz
     * @date: 2021/4/25
     */
    onSearch() {
      this.$refs.form.validate(valid => {
        if (valid) {
          this.$emit("onSearch", this.form);
        } else {
          // console.log("error submit!!");
          return false;
        }
      });
    },
    /**
     * @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);
          }
        }
      }
    }
  }
};
</script>

<style scoped></style>


# 引入页面

src/views/home.vue

<template>
  <div>
    <div>
      <MyForm
        :form="formData.form"
        :inline="true"
        :search="true"
        :searchText="'立刻查询'"
        :options="formData.options"
        :rules="formData.rules"
        :labelWidth="formData.labelWidth"
        @onSearch="onSearch"
      ></MyForm>
      <el-divider></el-divider>
      <MyForm
        :form="formData.form"
        :options="formData.options"
        :rules="formData.rules"
        :labelWidth="formData.labelWidth"
        @onSearch="onSearch"
      ></MyForm>
      <el-divider></el-divider>
    </div>
  </div>
</template>

<script>
import MyForm from "@/components/Form.vue";
export default {
  name: "home",
  components: {
    MyForm
  },
  data() {
    return {
      formData: {
        form: {
          date: "",
          sex: "",
          name: ""
        },
        options: [
          {
            title: "日期",
            key: "date",
            type: "date",
            rules: true
          },
          {
            title: "性别",
            key: "sex",
            type: "select",
            option: {
              data: [
                {
                  id: 1,
                  title: "女",
                  type: 0
                },
                {
                  id: 2,
                  title: "男",
                  type: 1
                }
              ],
              key: "id", // 指定key对应data的字段
              label: "title", // 指定label对应data的字段
              value: "type" // 指定value对应data的字段
            }
          },
          {
            title: "名字",
            key: "name",
            type: "input",
            rules: true
          }
        ],
        rules: {},
        labelWidth: "80px"
      }
    };
  },
  mounted() {},
  methods: {
    // 搜索
    onSearch(data) {
      console.log(data);
    }
  }
};
</script>

<style scoped></style>


# 自定义图片上传

<template>
  <div>
    <div>
      <MyForm
        :form="formData.form"
        :options="formData.options"
        :rules="formData.rules"
        :labelWidth="formData.labelWidth"
        @onSearch="onSearch"
      >
        <template slot="file">
          <el-form-item label="文件上传">
            <el-upload
              action=""
              :show-file-list="false"
              :on-change="handleChange"
              :auto-upload="false"
            >
              <img v-if="formData.form.img" :src="formData.form.img" alt="" />
              <i v-else class="el-icon-plus avatar-uploader-icon"></i>
            </el-upload>
          </el-form-item>
        </template>
      </MyForm>
      <el-divider></el-divider>
    </div>
  </div>
</template>

<script>
import MyForm from "@/components/Form.vue";
export default {
  name: "home",
  components: {
    MyForm
  },
  data() {
    return {
      formData: {
        form: {
          date: ""
        },
        options: [
        ],
        rules: {},
        labelWidth: "80px"
      }
    };
  },
  mounted() {},
  methods: {
    handleChange(file, fileList) {
      fileList;
      this.formData.form.img = URL.createObjectURL(file.raw);
    }
  }
};
</script>

<style></style>

使用 template 包含自定义的内容,slot一定要是file

上传组件根据业务而定,我预留了一个slot插槽用来显示自定义的上传组件



# 参数说明

属性 描述 默认值 必需
form form表单 {}
options 表单配置 []
inline 是否开启行内表单 false
search 是否开启搜索 false
searchText 搜索按钮文字 查询
rules 表单验证规则 {}
labelWidth 表单表头宽度 80px
size 控件大小 medium


# options

属性 描述 必需
title 表单表头
key 表单对应的字段
type 控件类型
rules 是否开启验证


# type

属性 描述
input 输入框
text 文本输入框
switch 开关
time 时间
date 日期
datetime 日期时间
date-to-date 开始日期 — 结束日期
datetime-to-datetime 开始日期时间 — 结束日期时间
number 数字
select 选择框
radio 单选框
checkbox 多选框

checkbox绑定字段的值一定要是: []

例如:checkbox: []



# option

只有在type[select, radio, checkbox]时才需要设置

属性 描述 必需
data 数据源
Key 指定key对应data的唯一字段
label 指定label对应data的显示标题字段
value 指定value对应data的值字段


# 方法

属性 描述 回调函数
@onSearch 搜索事件 form


# 效果图



# 更多表单

<template>
  <div>
    <div>
      <MyForm
        :form="formData.form"
        :options="formData.options"
        :rules="formData.rules"
        :labelWidth="formData.labelWidth"
      >
      </MyForm>
      <el-divider></el-divider>
    </div>
  </div>
</template>

<script>
import MyForm from "@/components/Form.vue";
export default {
  name: "home",
  components: {
    MyForm
  },
  data() {
    return {
      formData: {
        form: {
          input: "",
          text: "",
          switch: true,
          time: "10:10:10",
          date: "2021-04-27",
          datetime: "2021-04-27 10:10:10",
          "date-to-date": "",
          "datetime-to-datetime": "",
          number: 0,
          select: "",
          radio: "",
          checkbox: []
        },
        options: [
          {
            title: "输入框",
            key: "input",
            type: "input"
          },
          {
            title: "文本",
            key: "text",
            type: "text"
          },
          {
            title: "开关",
            key: "switch",
            type: "switch"
          },
          {
            title: "时间",
            key: "time",
            type: "time"
          },
          {
            title: "日期",
            key: "date",
            type: "date"
          },
          {
            title: "日期时间",
            key: "datetime",
            type: "datetime"
          },
          {
            title: "开始日期 --- 结束日期",
            key: "date-to-date",
            type: "date-to-date"
          },
          {
            title: "开始日期时间 --- 结束日期时间",
            key: "datetime-to-datetime",
            type: "datetime-to-datetime"
          },
          {
            title: "数字",
            key: "number",
            type: "number"
          },
          {
            title: "选择框",
            key: "select",
            type: "select",
            option: {
              data: [
                {
                  id: 1,
                  title: "女",
                  type: 0
                },
                {
                  id: 2,
                  title: "男",
                  type: 1
                }
              ],
              key: "id", // 指定key对应data的字段
              label: "title", // 指定label对应data的字段
              value: "type" // 指定value对应data的字段
            }
          },
          {
            title: "单选框",
            key: "radio",
            type: "radio",
            option: {
              data: [
                {
                  id: 1,
                  title: "女",
                  type: 0
                },
                {
                  id: 2,
                  title: "男",
                  type: 1
                }
              ],
              key: "id", // 指定key对应data的字段
              label: "title", // 指定label对应data的字段
              value: "type" // 指定value对应data的字段
            }
          },
          {
            title: "多选框",
            key: "checkbox",
            type: "checkbox",
            option: {
              data: [
                {
                  id: 1,
                  title: "1"
                },
                {
                  id: 2,
                  title: "2"
                },
                {
                  id: 3,
                  title: "3"
                }
              ],
              key: "id", // 指定key对应data的字段
              label: "title" // 指定label对应data的字段
            }
          }
        ],
        rules: {},
        labelWidth: "250px"
      }
    };
  },
  mounted() {},
  methods: {}
};
</script>

<style></style>


# 效果图


转载:https://blog.csdn.net/weixin_42863549/article/details/116167827
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场