vue2 + antd 封装动态表单组件(二)

前置条件,请先浏览

vue2 + antd 封装动态表单组件(一)

需求场景,当国家控件选择为“美国”时,要求:

  1. 禁用“姓名”输入框
  2. 隐藏“兴趣爱好”多选框
  3. “个人简介”由选填改为必填

动态表单组件dynamic-form.vue新增hidden属性控制显示隐藏,新增disabled属性控制是否禁用
vue2 + antd 封装动态表单组件(二)_第1张图片
新增对应的配置项,如
vue2 + antd 封装动态表单组件(二)_第2张图片

废话少说,直接上完整代码:

dynamic-form.vue文件

<template>
  <div>
    <a-form :form="form" ref="form" :label-col="labelCol" :wrapper-col="wrapperCol">
      <div v-for="field in fieldItemOptions" :key="field.key">
        <a-form-item :label="field.label" :required="field.required" v-if="!field.hidden">
          
          <template v-if="field.type === 'text'">
            <a-input
              v-decorator="[
              field.key,
              {
                rules: [{ required: field.required, message: `${field.label}不能为空` }],
                initialValue: field.value 
              },
            ]"
              :placeholder="`请输入${field.label}`"
              :disabled="field.disabled"
            >a-input>
          template>

          
          <template v-else-if="field.type === 'textarea'">
            <a-textarea
              v-decorator="[
              field.key,
              {
                rules: [{ required: field.required, message: `${field.label}不能为空` }],
                initialValue: field.value 
              },
            ]"
              :placeholder="`请输入${field.label}`"
              :auto-size="{ minRows: field.minRows || 5, maxRows: field.maxRows || 8 }"
              :maxLength="field.max || 256"
              :disabled="field.disabled"
            />
          template>

          
          <template v-else-if="field.type === 'select'">
            <a-select
              :placeholder="`请选择${field.label}`"
              v-decorator="[
              field.key,
              {
                rules: [{ required: field.required, message: `请选择${field.label}` }],
                initialValue: field.value 
              },
            ]"
            >
              <a-select-option
                v-for="option in field.options"
                :key="option.value"
                :value="option.value"
              >{{option.label}}a-select-option>
            a-select>
          template>

          
          <template v-else-if="field.type === 'checkbox'">
            <a-checkbox-group
              v-decorator="[
              field.key,
              {
                rules: [{ required: field.required, message: `请选择${field.label}` }],
                initialValue: field.value
              },
            ]"
            >
              <a-checkbox
                v-for="option in field.options"
                :key="option.value"
                :value="option.value"
                :style="{width: field.width}"
              >{{option.label}}a-checkbox>
            a-checkbox-group>
          template>

          
          <template v-else-if="field.type === 'radio'">
            <a-radio-group
              v-decorator="[
              field.key,
              {
                rules: [{ required: field.required, message: `请选择${field.label}` }],
                initialValue: field.value 
              },
            ]"
            >
              <a-radio
                v-for="option in field.options"
                :key="option.value"
                :value="option.value"
              >{{option.label}}a-radio>
            a-radio-group>
          template>
        a-form-item>
      div>
    a-form>
    <a-button type="primary" @click="handleSubmit()">提交a-button>
  div>
template>

<script>
import { deepClone } from "@/common/utils";
export default {
  props: {
    // 表单域配置
    fieldOptions: {
      type: Array,
      default: () => []
    },

    // 编辑时表单回显的默认数据
    model: {
      type: Object,
      default: () => ({})
    },

    // 标签宽度
    labelCol: {
      type: Object,
      default: () => {
        return {
          xs: { span: 24 },
          sm: { span: 6 }
        };
      }
    },

    // 控件宽度
    wrapperCol: {
      type: Object,
      default: () => {
        return {
          xs: { span: 24 },
          sm: { span: 16 }
        };
      }
    }
  },

  watch: {
    fieldOptions: {
      handler(fieldOptions) {
        this.fieldItemOptions = deepClone(fieldOptions);
        // 回显默认值
        const defaultValue = fieldOptions.reduce((pre, cur) => {
          if (![null, undefined, ''].includes(cur.value)) {
            pre[cur.key] = cur.value;
          }
          return pre;
        }, {});
        this.setFieldItemOptionsValue({ ...defaultValue, ...this.model })
      },
      deep: true,
      immediate: true
    }
  },

  computed: {

  },

  data() {
    return {
      fieldItemOptions: [],
      // 表单
      form: this.$form.createForm(this, {
        onValuesChange: (props, values) => {
          this.setFieldItemOptionsValue(values)
        }
      })
    };
  },
  methods: {
    // 提交表单
    handleSubmit() {
      this.form.validateFields((err, formData) => {
        if (err) {
          return;
        }
        // 提交表单逻辑
      });
    },

    // 更新表单value值
    setFieldItemOptionsValue(values) {
      this.fieldItemOptions.forEach(c => {
        this.fieldOptions.forEach(d => {
          if (c.key === d.key) {
            for (const k in d) {
              // 若为函数类型则执行
              c[k] =
                typeof d[k] == "function"
                  ? d[k]({ ...this.form.getFieldsValue(), ...values })
                  : c[k];
            }
          }
        });
        for (const key in values) {
          if (c.key === key) {
            c.value = values[key];
          }
        }
      });
    }
  },
  created() {}
};
script>

使用该动态表单dynamic-form.vue组件的文件

<template>
  <div>
    <dynamic-form
      ref="dynamicForm"
      :fieldOptions="fieldOptions"
      :model="model"
      :labelCol="labelCol"
      :wrapperCol="wrapperCol"
    >dynamic-form>
  div>
template>

<script>
import DynamicForm from "./dynamic-form.vue";
export default {
  components: {
    DynamicForm
  },
  data() {
    return {
      fieldOptions: [
        {
          label: "姓名",
          key: "name",
          value: "",
          type: "text",
          required: true,
          disabled: formData => {
            return formData.country === 2
          }
        },
        {
          label: "性别",
          key: "sex",
          value: 1,
          type: "radio",
          required: true,
          options: [
            {
              value: 1,
              label: "男"
            },
            {
              value: 2,
              label: "女"
            }
          ]
        },
        {
          label: "兴趣爱好",
          key: "hobby",
          value: [],
          type: "checkbox",
          required: true,
          options: [
            {
              value: 1,
              label: "足球"
            },
            {
              value: 2,
              label: "篮球"
            },
            {
              value: 3,
              label: "排球"
            }
          ],
          hidden: formData => {
            return formData.country === 2
          }
        },
        {
          label: "国家",
          key: "country",
          value: undefined,
          type: "select",
          required: true,
          options: [
            {
              value: 1,
              label: '中国'
            },
             {
              value: 2,
              label: '美国'
            },
             {
              value: 3,
              label: '俄罗斯'
            }
          ]
        },
        {
          label: "个人简介",
          key: "desc",
          value: "",
          type: "textarea",
          required: formData => formData.country === 2
        }
      ],
      model: {
        name: '动态表单',
        sex: 2,
        hobby: [1, 2], 
        country: 1,
        desc: '这是一个简单的例子'
      },
      labelCol: {
        xs: { span: 24 },
        sm: { span: 6 }
      },
      wrapperCol: {
        xs: { span: 24 },
        sm: { span: 16 }
      }
    };
  }
};
script>

实现效果如下:

vue2 + antd 封装动态表单组件(二)_第3张图片

你可能感兴趣的:(vue,antd,vue)