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

前置条件:

vue版本 v3.3.11
ant-design-vue版本 v4.1.1

创建动态组件配置文件config.js

import {
    Input, Textarea, InputNumber, Select, RadioGroup, CheckboxGroup, DatePicker } from 'ant-design-vue';

// 表单域组件类型
export const componentsMap = {
   
    Text: Input,
    Textarea,
    Number: InputNumber,
    Select,
    Radio: RadioGroup,
    Checkbox: CheckboxGroup,
    DatePicker,
}

创建dynamic-form.vue组件

<template>
  <div>
    <a-form ref="formRef" :model="formModel">
      <a-form-item
        :name="item.field"
        :label="item.label"
        v-for="item in formSchema"
        :key="item.field"
        v-bind="item.formItemProps"
      >
        <component
          :is="componentsMap[item.component]"
          v-bind="item.componentProps"
          v-model:value="formModel[item.field]"
        />
      </a-form-item>
    </a-form>
  </div>
</template>

<script setup>
import {
      ref, watch, onMounted } from "vue";
import {
      componentsMap } from "./config.js";

const props = defineProps({
     
  // 表单项配置
  schema: {
     
    type: Array,
    default: () => [],
  },
  // 表单model配置,一般用于默认值、回显数据
  model: {
     
    type: Object,
    default: () => ({
     }),
  },
});

const formRef = ref(null);

const formSchema = ref([]);
const formModel = ref({
     });

// 表单初始化
const initForm = () => {
     
  formSchema.value = props.schema.map((x) => {
     
    return {
     
      ...x,
    };
  });

  // model初始数据
  formModel.value = props.schema.reduce((pre, cur) => {
     
    if (!pre[cur.field]) {
     
      // 表单初始数据(默认值)
      pre[cur.field] = cur.value;
      return pre;
    }
  }, {
     });
};

onMounted(() => {
     
  initForm();
  // 构建表单项后才回显model值,model会覆盖schema配置的value值
  watch(
    () => props.model,
    (newVal) => {
     
      formModel.value = {
      ...formModel.value, ...newVal };
    },
    {
     
      immediate: true,
      deep: true,
    }
  );
});

// 表单验证
const validateFields = () => {
     
  return new Promise((resolve, reject) => {
     
    formRef.value
      .validateFields()
      .then((formData) => {
     
        resolve(formData);
      })
      .catch((err) => reject(err));
  });
};

// 表单重置
const resetFields = (isInit = true) => {
     
  // 是否清空默认值
  if (isInit) {
     
    formModel.value = {
     };
  }
  formRef.value.resetFields();
};

// 暴露方法
defineExpose({
     
  validateFields,
  resetFields,
});
</script>

使用dynamic-form.vue组件

<template>
  <div style="padding: 200px">
    <DynamicForm ref="formRef" :schema="schema" :model="model" />
    <div style="display: flex; justify-content: center">
      <a-button @click="handleReset(true)">重置(全部清空)</a-button>
      <a-button style="margin-left: 50px" @click="handleReset(false)"
        >重置</a-button
      >
      <a-button type="primary" style="margin-left: 50px" @click="handleSubmit"
        >提交</a-button
      >
    </div>
  </div>
</template>

<script setup>
import DynamicForm from "@/components/form/dynamic-form.vue";
import {
      ref } from "vue";
import dayjs from "dayjs";
const formRef = ref(null);

const schema = ref([
  {
     
    label: "姓名",
    field: "name",
    component: "Text",
    componentProps: {
     
      allowClear: true,
      showCount: true,
      maxlength: 20,
      style: {
     
        width: "500px",
      },
    },
    formItemProps: {
     
      rules: [
        {
     
          required: true,
          message: "请输入姓名",
          trigger: "blur",
        },
      ],
    },
  },
  {
     
    label: "性别",
    field: "sex",
    component: "Radio",
    componentProps: {
     
      options: [
        {
      value: 1, label: "男" },
        {
      value: 2, label: "女" },
        {
      value: 3, label: "保密" },
      ],
    },
    formItemProps: {
     
      rules: [
        {
     
          required: true,
          message: "请选择性别",
          trigger: "blur",
        },
      ],
    },
    value: 1,
  },
  {
     
    label: "生日",
    field: "birthday",
    component: "DatePicker",
    formItemProps: {
     
      rules: [
        {
     
          required: true,
          message: "生日日期不能为空",
          trigger: "blur",
        },
      ],
    },
  },
  {
     
    label: "兴趣",
    field: "hobby",
    component: "Checkbox",
    componentProps: {
     
      options: [
        {
      value: 1, label: "足球" },
        {
      value: 2, label: "篮球" },
        {
      value: 3, label: "排球" },
      ],
    },
  },
  {
     
    label: "国家",
    field: "country",
    component: "Select",
    componentProps: {
     
      allowClear: true,
      options: [
        {
      value: 1, label: "中国" },
        {
      value: 2, label: "美国" },
        {
      value: 3, label: "俄罗斯" },
      ],
    },
  },
  {
     
    label: "简介",
    field: "desc",
    component: "Textarea",
    componentProps: {
     
      allowClear: true,
      autoSize: {
     
        minRows: 4,
        maxRows: 4,
      },
      maxlength: 200,
      showCount: true,
    },
  },
]);
const model = ref({
      name: "百里守约" });
// 提交
const handleSubmit = async () => {
     
  const formData = await formRef.value.validateFields();
  if (formData.birthday) {
     
    formData.birthday = dayjs(formData.birthday).format("YYYY-MM-DD");
  }
  console.log("提交信息:", formData);
};

// 重置
const handleReset = (isInit) => {
     
  formRef.value.resetFields(isInit);
};
</script>

效果图
在这里插入图片描述

相关推荐

  1. vue2 elementui 封装一个动态复杂组件

    2024-01-20 09:34:05       21 阅读
  2. vue2-组件封装

    2024-01-20 09:34:05       10 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-01-20 09:34:05       18 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-01-20 09:34:05       19 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-01-20 09:34:05       19 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-01-20 09:34:05       20 阅读

热门阅读

  1. var 和 let 的优缺点

    2024-01-20 09:34:05       40 阅读
  2. python爬虫如何写,有哪些成功爬取的案例

    2024-01-20 09:34:05       30 阅读
  3. mysql怎么开启一个事务

    2024-01-20 09:34:05       37 阅读
  4. 344. 观光之旅(最小环问题,Floyd)

    2024-01-20 09:34:05       34 阅读
  5. Docker的安装和使用

    2024-01-20 09:34:05       33 阅读
  6. Redis多线程模型探究

    2024-01-20 09:34:05       22 阅读
  7. 【Spring Boot 3】【Redis】分布式唯一ID生成器

    2024-01-20 09:34:05       35 阅读
  8. 「HDLBits题解」Latches and Flip-Flops

    2024-01-20 09:34:05       32 阅读