Skip to content

el-form表单封装

缘由

系统页面大部分为form+tabel的结构,系统复杂起来代码就看起来非常冗余,要修改起来也很麻烦,于是决定将表单封装起来。

结构

  1. 业务与逻辑区分

    • 新建const.js文件,处理表单逻辑
  2. 配置化

    • json对象化配置表单属性
  3. 扩展&特殊处理

    • 配置slot插槽

开始

html
<template>
  <el-form
    ref="form"
    :id="formConfig.id"
    :class="formConfig.className"
    :label-width="formConfig.labelWidth || '100px'"
    :size="formConfig.size || 'medium'"
    :rules="formConfig.rules"
    :model="formData"
  >
      <template
        v-for="(item, index) in getConfigList()"
        :key="index"
      >
        <el-form-item
          :prop="item.value"
          :label="item.label"
          :label-width="item.labelWidth"
          :class="item.className"
        >
          <!-- solt -->
          <template v-if="item.type === 'slot'">
            &lt;slot :name="'form-' + item.value" /&gt;
          </template>
          &lt;component
            :is="item.type"
            v-model="formData[item.value]"
            :type="item.dataType"
            :picker-options="item.timePickerOptions"
            :clearable="item.clearable"
            :disabled="item.disabled"
            :start-placeholder="item.startPlaceholder"
            :end-placeholder="item.endPlaceholder"
            :range-separator="item.rangeSeparator || '-'"
            :filterable="item.filterable"
            :multiple="item.multiple"
            :collapse-tags="item.collapseTags"
            default-first-option
            :allow-create="item.allowCreate"
            :no-data-text="item.noDataText || ''"
            :placeholder="getPlaceholder(item)"
            :value-format="item.valueFormat"
            :format="item.valueFormat"
            :style="{ width: item.width || '100%' }"
            :maxlength="item.maxLength"
            :autosize="item.autosize || { minRows: 2, maxRows: 10 }"
            @click="handleEvent(item.event, formData[item.value], 'click')"
            @change="handleEvent(item.event, formData[item.value], 'change')"
            @input="handleEvent(item.event, formData[item.value], 'input')"
            @blur="handleEvent(item.event, formData[item.value], 'blur')"
          &gt;
            <template v-if="item.type === 'el-select'">
              <el-option
                v-for="(childItem, childIndex) in listTypeInfo[item.list]"
                :key="`${childItem.value}${childIndex}`"
                :label="childItem.label"
                :value="childItem.value"
              ></el-option>
            </template>
            {{ item.title || '' }}
          &lt;/component&gt;
        </el-form-item>
   </template>
  </el-form>
</template>
<script>

export default {
  name: 'FormItemComp',
  data() {
    return { formData: {} };
  },
  props: {
    // 表单配置项
    formConfig: {
      type: Object,
      default: () => {},
    },
    // 表单数据
    data: { type: Object },
    // 下拉选项list
    listTypeInfo: { type: Object },
    // ref
    refObj: { type: Object },
  },
  watch: {
    data: {
      handler(val) {
        if (!val) return;
        this.formData = val;
        // 将form实例返回到父级
        this.$emit('update:refObj', this.$refs.form);
      },
      deep: true,
    },
  },
  mounted() {
    this.formData = this.data;
    // 将form实例返回到父级
    this.$emit('update:refObj', this.$refs.form);
  },
  methods: {
    // 获取字段列表
    getConfigList() {
      return this.formConfig.fieldList.filter(
        (item) => !Object.prototype.hasOwnProperty.call(item, 'show')
          || (Object.prototype.hasOwnProperty.call(item, 'show') && item.show),
      );
    },
    // 得到placeholder的显示
    getPlaceholder(row) {
      let placeholder;
      const types = ['el-select', 'el-date-picker'];
      if (row.type === 'el-input') {
        placeholder = `请输入${row.placeholder || ''}`;
      } else if (types.includes(row.type)) {
        placeholder = `请选择${row.placeholder || ''}`;
      } else {
        placeholder = row.label;
      }
      return placeholder;
    },
    // 表单事件派发
    handleEvent(event, data, type) {
      this.$emit('handleEvent', { event, data, type });
    },
  },
};
</script>

使用

js
// const.js
export const FormJson =  {
  id: 'form',
  rules: {},
  labelWidth: '100px',
  size: 'mini',
  className: 'el-form-component',
  fieldList: [
    {
      label: '名称:',
      value: 'name',
      type: 'el-select',
      clearable: true,
      list: 'nameList',
    },
    {
      label: '来源:',
      value: 'source',
      type: 'el-select',
      clearable: true,
      list: 'formSelect1',
    },
    {
      label: '主体:',
      value: 'subject',
      type: 'el-input',
    },
    {
      label: '分类:',
      value: 'nature',
      type: 'el-select',
      clearable: true,
      list: 'formSelect2',
    },
    {
      label: '日期:',
      value: 'date',
      type: 'el-date-picker',
      dataType: 'daterange',
      valueFormat: 'yyyy-MM-dd',
      startPlaceholder: '开始日期',
      endPlaceholder: '结束日期',
      rangeSeparator: '至',
      clearable: true,
    },
    {
      label: '状态:',
      value: 'status',
      type: 'el-select',
      clearable: true,
      list: 'projectStatus',
    },
    // slot插槽
    {
      label: '',
      value: 'btn',
      type: 'slot',
      colWidth: 18,
      className: 'text-right',
    },
  ],
};
html
<template>
    &lt;FormItemComp
        :formConfig="FormJson"
        :refObj.sync="formRef"
        :data="formData"
        :listTypeInfo="listTypeInfo"
        @handleEvent="handleEvent"
    &gt;
    <template slot="form-btn">
        <div>
            <el-button type="search" @click="">查询</el-button>
            <el-button type="reset" @click="">重置</el-button>
        </div>
    </template>
    &lt;/FormItemComp&gt;
</template>

<script>
import FormItemComp from './FormItemComp'
import { FormJson } from './const.js'
export default {
    data(){
        return {
            FormJson,
            formRef: null, // form ref
            formData: {
                name: '',
                source: '',
                subject: '',
                nature: '',
                date: '',
                status: '',
            },
            // el-select选项
            listTypeInfo: {
                formSelect1:[],
                formSelect2:[],
                projectStatus:[],
                nameList:[],
            }

        }
    },
    components: { FormItemComp },

    methods: {
    // 表单的相关事件
    handleEvent(val) {

    }
}
</script>