简单的表单组件封装

140 阅读3分钟
  1. 引入comForm组件
   <ComForm
       :formColumn="addFormColumn"
       :formData="addFormData"
       :layout="formLayout"
   ></ComForm>
  1. 相关的数据配置,这里用到的是vue3的语法
const addFormColumn = ref([
      {
        label: '标题:',
        type: 'input',
        visible: true,
        name: 'title',
        lableStyle: addLableStyle,
        valueStyle: addValueStyle,
        itemStyle: addItemStyle,
        required: true
      },
      {
        label: '内容:',
        type: 'textarea',
        visible: true,
        name: 'content',
        lableStyle: addLableStyle,
        valueStyle: { ...addValueStyle, width: '80rem', height: '12rem' },
        itemStyle: addItemStyle
      }
    ]);
    const addFormData = reactive({
      title: '',
      content: ''
    });
  1. 样式设置
  const addLableStyle = {
      width: '8rem',
      height: '3.5rem',
      lineHeight: '3.5rem'
    };

    const addValueStyle = {
      width: '30rem',
      height: '3.5rem',
      lineHeight: '3.5rem'
    };
    const addItemStyle = {
      marginBottom: '2rem'
    };
    const formLayout = {
      layout: 'inline'
    };

4.编写comForm组件

<template>
  <div id="comForm">
    <a-form
      ref="form"
      :class="isBorder ? 'form-border' : null"
      :layout="layout.layout"
      :model="formData"
      name="basic"
      :label-col="{ span: 8 }"
      :wrapper-col="{ span: 16 }"
      autocomplete="off"
    >
      <a-form-item
        v-for="(item, index) in formColumn"
        :style="item.itemStyle ? item.itemStyle : null"
        :key="index"
        :label="item.label ? item.label : null"
        :labelCol="{ style: item.lableStyle ? item.lableStyle : null }"
        :name="item.name"
        labelAlign="right"
        :rules="
          item.pattern
            ? [
                {
                  required: item.required ? item.required : false,
                  pattern: item.newRules ? item.newRules.pattern : '',
                  message: item.newRules.message
                }
              ]
            : [
                {
                  required: item.required ? item.required : false,
                  message: item.label + '不能为空'
                }
              ]
        "
      >
        <a-input
          v-if="item.type === 'input' && item.visible"
          :allowClear="item.allowClear ? item.allowClear : false"
          :disabled="item.disabled || false"
          @change="(value) => selectChange(value, item.name)"
          v-model:value="formData[item.name]"
          key="

        "
          :style="item.valueStyle ? item.valueStyle : null"
        />

        <!-- 添加了前缀 -->
        <a-input
          v-if="item.type === 'pre-input' && item.visible"
          :allowClear="item.allowClear ? item.allowClear : false"
          :disabled="item.disabled || false"
          @change="(value) => selectChange(value, item.name)"
          v-model:value="formData[item.name]"
          key=""
          :style="item.valueStyle ? item.valueStyle : null"
          :placeholder="item.placeholder ? item.placeholder : '请输入内容'"
        >
          <template #prefix>
            <user-outlined type="user" />
          </template>
        </a-input>

        <a-input-password
          v-if="item.type === 'passWord' && item.visible"
          v-model:value="formData[item.name]"
          key=""
          :placeholder="item.placeholder ? item.placeholder : '请输入内容'"
          :style="item.valueStyle ? item.valueStyle : null"
        >
          <template #prefix>
            <lock-outlined />
          </template>
        </a-input-password>

        <a-date-picker
          v-else-if="item.type === 'date' && item.visible"
          :locale="locale"
          v-model:value="formData[item.name]"
          :style="item.valueStyle ? item.valueStyle : null"
          format="YYYY-MM-DD"
          value-format="YYYY-MM-DD"
          @change="(value) => selectChange(value, item.name)"
          :disabled-date="item.disabled ? disabledDate : null"
        />
        <a-time-picker
          :locale="locale"
          v-else-if="item.type === 'time' && item.visible"
          v-model:value="formData[item.name]"
          :style="item.valueStyle ? item.valueStyle : null"
          format="HH:mm"
          value-format="HH:mm"
          @change="(value) => selectChange(value, item.name)"
          :popup-style="popupStyle"
        />

        <a-select
          v-else-if="item.type === 'select' && item.visible"
          :placeholder="item.placeholder ? item.placeholder : '请输入内容'"
          :disabled="item.disabled || false"
          :mode="
            item.mode == 'multiple'
              ? 'multiple'
              : item.mode == 'tags'
              ? 'tags'
              : 'null'
          "
          :allowClear="item.allowClear ? item.allowClear : false"
          :style="item.valueStyle ? item.valueStyle : null"
          @change="(value) => selectChange(value, item.name, item)"
          :filter-option="filterOption"
          show-search
          v-model:value="formData[item.name]"
          :options="item.options"
        >
          <!-- <a-select-option
            v-for="(_item, _index) in item.options"
            :key="_index"
            :value="_item.value"
          >
            {{ _item.label }}
          </a-select-option> -->
        </a-select>

        <a-select
          v-else-if="item.type === 'inputSelect' && item.visible"
          v-model:value="formData[item.name]"
          show-search
          :placeholder="item.placeholder ? item.placeholder : '请输入内容'"
          style="width: 200px"
          :disabled="item.disabled || false"
          :show-arrow="true"
          :not-found-content="null"
          :allowClear="item.allowClear ? item.allowClear : false"
          :options="item.options"
          :style="item.valueStyle ? item.valueStyle : null"
          :filter-option="true"
          @search="(value) => handleInputSelectSearch(value, item.name, item)"
          @change="(value) => handleInputChange(value, item.name, item)"
        ></a-select>

        <a-textarea
          :allowClear="item.allowClear ? item.allowClear : false"
          v-model:value="formData[item.name]"
          v-else-if="item.type === 'textarea' && item.visible"
          :style="item.valueStyle ? item.valueStyle : null"
          :disabled="item.disabled || false"
          @change="(value) => selectChange(value, item.name)"
        />

        <a-checkbox-group
          v-else-if="item.type === 'checkBoxUnit' && item.visible"
          v-model:value="formData[item.name]"
          :options="item.options"
        >
        </a-checkbox-group>

        <a-checkbox
          v-model:checked="formData[item.name]"
          v-else-if="item.type === 'checkbox' && item.visible"
        >
          {{ item.title }}
        </a-checkbox>
        <!-- 这里利用绑定v-model:id父子组件来实现绑定 避免孙子组件向爷爷组件传值 -->
        <div v-else-if="item.type === 'companyId' && item.visible">
          <ComCascader
            v-model:companyId="formData[item.name]"
            :style="item.valueStyle ? item.valueStyle : null"
            :unitAllData="item.options"
            :isDidsabled="isDidsabled"
          ></ComCascader>
        </div>

        <div v-if="item.visible && item.boTip" style="color: red">
          {{ item.boTip }}
        </div>
      </a-form-item>
    </a-form>

    <slot name="button"></slot>
  </div>
</template>

<script lang="ts">
import {
  defineComponent,
  reactive,
  ref,
  toRefs,
  warn,
  onMounted,
  inject,
  toRaw,
  nextTick
} from 'vue';
import {
  ISearchFormColumn,
  ISearchFormData
} from '@/views/support/airport/type';
import locale from 'ant-design-vue/es/date-picker/locale/zh_CN';
import dayjs from 'dayjs';
import ComCascader from '../cascader/ComCascader.vue';
import { UserOutlined, LockOutlined } from '@ant-design/icons-vue';

export default defineComponent({
  name: '',
  props: {
    isBorder: {
      default: false,
      type: Boolean
    },

    formColumn: {
      default: function () {
        return [];
      }
      // type: Array as () => ISearchFormColumn[]
      // type: Array
    },

    formData: {
      type: Object,
      default: function () {
        return {};
      }
    },
    layout: {
      type: Object,
      default: function () {
        return {};
      }
    },
    isDidsabled: {
      type: Boolean
    }
  },
  emits: [],
  setup(props, { attrs, slots, emit, expose }) {
    const newFormData = ref(props['formDat']);
    const form = ref(null);

    //  props.formColumn.forEach((item)=>{
    //   item.visible=true
    //  })
    const data = reactive({}); //里面写所有的响应式数据,像vue2中的data一样
    const bgColor = ref('');
    //祖孙组件传值
    const updateToGrandFather = inject('updateArea');
    const checkValidateTo = inject('checkValidate');
    const airPortEditArea = inject('toAirPortEditChange');

    const selectChange = (value, name, item) => {
      emit('toSelectChang', value, name, item);
      if (typeof updateToGrandFather == 'function') {
        updateToGrandFather(value, name);
      }
    };

    const filterOption = (input: string, option: any) => {
      return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0;
    };
    //搜素输入框的事件祖孙之间传值
    const seachValueToGrandF = inject('updateSelectValue');

    const handleInputSelectSearch = (
      value: string,
      nType: string,
      record: object
    ) => {
      emit('handleInputSelectSearch', value, nType, record);
    };

    const handleInputChange = (
      value: string,
      nType: string,
      record: object
    ) => {
      emit('handleInputChange', value, nType, record);
    };

    //回调显示是否通过校验
    const validate = (calback) => {
      form.value
        .validate()
        .then(() => {
          calback(true);
        })
        .catch(() => {
          calback(false);
        });
    };

    const popupStyle = {
      width: '14rem',
      textAlign: 'center'
    };

    const disabledDate = (current) => {
      return current && current >= dayjs().startOf('day');
    };

    return {
      filterOption,
      locale,
      dayjs,
      validate,
      ...toRefs(data),
      selectChange,
      form,
      checkValidateTo,
      handleInputSelectSearch,
      handleInputChange,
      seachValueToGrandF,
      newFormData,
      popupStyle,
      disabledDate
    };
  },
  components: { ComCascader, UserOutlined, LockOutlined }
});
</script>

<style lang="scss" scoped>
// 公共组件尽量少些静态样式
textarea.ant-input {
  max-width: none !important;
  resize: none;
}

/deep/.ant-checkbox-wrapper {
  > span:nth-child(2) {
    width: 12rem;
  }
}
</style>