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

2 篇文章 0 订阅
本文展示了如何在 Vue2 与 Ant Design 的动态表单组件中,根据国家选择(美国)动态调整表单字段:禁用姓名输入,隐藏兴趣爱好多选,将个人简介设为必填。通过新增配置项和代码实现,详细展示了如何使用hidden和disabled属性进行控制。
摘要由CSDN通过智能技术生成
前置条件,请先浏览

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

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

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

动态表单组件dynamic-form.vue新增hidden属性控制显示隐藏,新增disabled属性控制是否禁用
在这里插入图片描述
新增对应的配置项,如
在这里插入图片描述

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

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">
          <!-- text文本框 -->
          <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>

          <!-- textarea 文本域 -->
          <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>

          <!-- select下拉框 -->
          <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>

          <!-- checkbox多选框 -->
          <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>

          <!-- radio单选框 -->
          <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>

实现效果如下:

在这里插入图片描述

Vue-cli是一个官方推出的Vue项目脚手架工具,用于快速搭建Vue项目。ts是TypeScript的简称,是一种由微软开发的开源编程语言,它是JavaScript的超集,可以为JavaScript代码添加静态类型检查和封装类、模块等面向对象编程的特性。antd是蚂蚁金服开源的一套基于React封装的UI组件库,提供了丰富的高质量的React组件。 将这三者结合在一起,意味着我们可以利用Vue-cli搭建一个基于Vue和TypeScript的项目,并使用antd组件库来构建界面。这样的项目结合了Vue的简洁、易用和高效性能,TypeScript的类型检查和面向对象编程特性,以及antd的高质量UI组件,可以提升开发效率和代码质量。 在使用Vue-cli创建项目时,可以选择使用TypeScript作为项目的开发语言,这样项目就会自动集成TypeScript的相关配置和支持。通过使用Vue-cli提供的命令和配置,我们可以快速搭建一个工程化的项目结构,并集成Webpack等构建工具。 在项目中使用antd组件库时,可以通过npm或者yarn安装antd包,然后在Vue组件中引入所需的组件,并进行相关配置和使用。antd提供了丰富的UI组件,包括按钮、表单、弹窗、表格等常见的界面元素,可以根据项目需求进行选择和使用。 在使用TypeScript编写Vue项目时,可以利用TypeScript的静态类型检查、类型提示功能,提升代码的可读性和可维护性。同时,可以使用面向对象的编程方式来组织代码,更好地管理和封装组件、模块等。 综上所述,使用Vue-cli搭建一个基于Vue、TypeScript和antd的项目,可以充分发挥各自的优势,提升开发效率和代码质量,同时能够满足丰富的UI界面需求。这样的项目具备良好的可扩展性和可维护性,适合于中大型前端项目的开发。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值