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

传送带:
vue3 + antd 封装动态表单组件(一)


前置条件:

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

vue3 + antd 封装动态表单组件(一)是基础版本,但是并不好用, 因为需要配置很多表单项的schem组件属性componentProps,如果很多地方用到这些表单项,就需要大量的重复工作去配置这些相同的组件属性。

因此,本篇文章新增了默认组件属性和表单项配置功能,大大简化了动态表单schema配置,请根据实际的业务场景进行配置;

动态组件配置文件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,
}// 配置各组件属性默认值,相关配置项请查看ant-design官网各组件api属性配置
export const defaultComponentProps = {Text: {allowClear: true,bordered: true,disabled: false,showCount: true,maxlength: 20,},Textarea: {allowClear: true,autoSize: { minRows: 4, maxRows: 4 },showCount: true,maxlength: 200,style: {width: '100%'}},Select: {allowClear: true,bordered: true,disabled: false,showArrow: true,optionFilterProp: 'label',optionLabelProp: 'label',showSearch: true,},DatePicker: {allowClear: true,bordered: true,disabled: false,format: 'YYYY-MM-DD',picker: 'date',style: {width: '100%'}},
}

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"><span v-if="item.loading"><LoadingOutlined style="margin-right: 4px" />数据加载中...</span><componentv-else: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, computed } from "vue";
import { componentsMap, defaultComponentProps } from "./config.js";
import { LoadingOutlined } from "@ant-design/icons-vue";
const props = defineProps({// 表单项配置schema: {type: Array,default: () => [],},// 表单model配置,一般用于默认值、回显数据model: {type: Object,default: () => ({}),},// 组件属性配置componentProps: {type: Object,default: () => ({}),},
});const formRef = ref(null);const formSchema = ref([]);
const formModel = ref({});// 组件placeholder
const getPlaceholder = (x) => {let placeholder = "";switch (x.component) {case "Text":case "Textarea":placeholder = `请输入${x.label}`;break;case "RangePicker":placeholder = ["开始时间", "结束时间"];break;default:placeholder = `请选择${x.label}`;break;}return placeholder;
};// 组件属性componentProps, 注意优先级:组件自己配置的componentProps > props.componentProps > config.js中的componentProps
const getComponentProps = (x) => {if (!x?.componentProps) x.componentProps = {};// 使得外层可以直接配置optionsif (x.hasOwnProperty("options") && x.options) {x.componentProps.options = [];const isFunction = typeof x.options === "function";const isArray = Array.isArray(x.options);if (isFunction || isArray) {// 函数时先赋值空数组x.componentProps.options = isFunction ? [] : x.options;}}return {placeholder: x?.componentProps?.placeholder ?? getPlaceholder(x),...(defaultComponentProps[x.component] || {}), // config.js带过来的基础componentProps默认配置...(props.componentProps[x.component] || {}), // props传进来的组件componentProps配置...x.componentProps, // 组件自身的componentProps};
};// 表单属性formItemProps
const getFormItemProps = (x) => {let result = {};// 使得外层可以直接配置required必填项if (x.hasOwnProperty("required") && x.required) {result.rules = [...(x?.formItemProps?.rules || []),{required: true,message: getPlaceholder(x),trigger: "blur",},];}return result;
};const getSchemaConfig = (x) => {return {...x,componentProps: getComponentProps(x),formItemProps: getFormItemProps(x),};
};// 表单初始化
const initForm = () => {formSchema.value = props.schema.map((x) => getSchemaConfig(x));// model初始数据formModel.value = props.schema.reduce((pre, cur) => {if (!pre[cur.field]) {// 表单初始数据(默认值)pre[cur.field] = cur.value;return pre;}}, {});// options-获取异步数据formSchema.value.forEach(async (x) => {if (x.options && typeof x.options === "function") {x.loading = true;x.componentProps.options = await x.options(formModel.value);x.loading = false;}});
};onMounted(() => {initForm();// 构建表单项后才回显model值,model会覆盖schema配置的value值watch(() => props.model,(newVal) => {formModel.value = { ...formModel.value, ...newVal };},{immediate: true,deep: true,});
});const hasLoadingSchema = computed(() =>formSchema.value.some((x) => x.loading)
);// 表单验证
const validateFields = () => {if (hasLoadingSchema.value) {console.log("正在加载表单项数据...");return;}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>

utils.js文件

// 用于模拟接口请求
export const getRemoteData = (data = '获取数据', time = 2000) => {return new Promise((resolve) => {setTimeout(() => {console.log(`模拟获取接口数据`, data)resolve(data)}, time)})
}

使用dynamic-form.vue组件,注意比较vue3 + antd 封装动态表单组件(一)中的表单项的schema配置

<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";
import { getRemoteData } from "@/common/utils";
const formRef = ref(null);const schema = ref([{label: "姓名",field: "name",component: "Text",required: true,},{label: "性别",field: "sex",component: "Radio",options: [{ value: 1, label: "男" },{ value: 2, label: "女" },{ value: 3, label: "保密" },],value: 1,required: true,},{label: "生日",field: "birthday",component: "DatePicker",required: true,},{label: "兴趣",field: "hobby",component: "Checkbox",options: async () => {// 后台返回的数据listconst list = [{ value: 1, label: "足球" },{ value: 2, label: "篮球" },{ value: 3, label: "排球" },];return await getRemoteData(list);},},{label: "国家",field: "country",component: "Select",options: [{ value: 1, label: "中国" },{ value: 2, label: "美国" },{ value: 3, label: "俄罗斯" },],},{label: "简介",field: "desc",component: "Textarea",},
]);
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>

效果图

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/647934.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【QT+QGIS跨平台编译】之八:【zstd+Qt跨平台编译】(一套代码、一套框架,跨平台编译)

文章目录 一、zstd介绍二、文件下载三、文件分析四、pro文件五、编译实践一、zstd介绍 ZSTD(Zstandard的缩写),是一种快速压缩算法,提供了高压缩比功能。ZSTD还为小数据提供了一种特殊的模式,称为字典压缩。ZSTD库使用BSD许可证作为开放源码软件提供的。它的格式是稳定的,…

【java题解】题目 1779: 你的第一个程序;题目 1779: 你的第一个程序;题目 1173: 计算球体积

目录 题目 1779: 你的第一个程序 题目描述 输入格式 输出格式 样例输入 样例输出 题解 题目 1173: 计算球体积 题目描述 输入格式 输出格式 样例输入 样例输出 题解 题目 1267: AB Problem 题目描述 输入格式 输出格式 样例输入 样例输出 题解 从今天开始…

TS学习笔记十:装饰器及三斜线指令

本节介绍TS中的装饰器和三斜线指令&#xff0c; 装饰器&#xff08;Decorators&#xff09;为我们在类的声明及成员上通过元编程语法添加标注提供了一种方式。   三斜线指令是包含单个XML标签的单行注释。 注释的内容会做为编译器指令使用。 讲解视频 20240116-205052装饰器…

基于一款热门大屏可视化设计器使用教程

乐吾乐大屏可视化设计器是一个用于创建和定制大屏幕数据可视化展示的工具&#xff0c;支持零代码实现物联网、工业智能制造等领域的可视化大屏、触摸屏端UI以及工控可视化的解决方案。同时也是一个Web组态工具&#xff0c;支持2D、3D等多种形式&#xff0c;用于构建具有实时数据…

华硕ASUS K43SD笔记本安装win7X64(ventoy为入口以支撑一盘多系统);友善之臂mini2440开发板学习

记录 老爷机 白色 华硕 K43SD 笔记本 安装 win7X64 1. MBR样式常规安装win7X64Sp1 (华硕 K43SD 安装 win7X64 ) 老爷机 白色 华硕 K43SD 笔记本 安装 win7X64 (常规安装) 设置: 禁用UEFI 启用AHCI ventoy制作MBR(非UEFI)方式的启动U盘 U盘中放cn_windows_7_ultimate_wit…

TCP 三次握手以及滑动窗口

TCP 三次握手 简介&#xff1a; TCP 是一种面向连接的单播协议&#xff0c;在发送数据前&#xff0c;通信双方必须在彼此间建立一条连接。所谓的 “ 连接” &#xff0c;其实是客户端和服务器的内存里保存的一份关于对方的信息&#xff0c;如 IP 地址、端口号等。 TCP 可以…

【机器学习300问】19、深度学习和机器学习什么关系?

之前的文章都聚焦在传统的机器学习上&#xff0c;作为入门&#xff0c;学了许多机器学习的基础。往后的文章我会穿插着机器学习和深度学习的内容进行&#xff0c;所有有必要在这里先说下两者的关系。 一、从范围上讲 深度学习和机器学习都是人工智能的一个子领域&#xff0c;它…

微信会议活动微展示在线活动报名源码系统 带完整的搭建教程

随着微信的普及&#xff0c;微信会议活动已成为企业、团体和个人进行信息交流、业务推广和品牌宣传的重要平台。然而&#xff0c;如何高效地管理、展示和报名参加这些会议活动&#xff0c;一直是许多组织者面临的难题。下面&#xff0c;小编给大家分享一款微信会议活动微展示在…

江科大STM32 中

目录 6、TIM&#xff08;Timer&#xff09;定时器基本定时器通用定时器高级定时器示例程序&#xff08;定时器定时中断&定时器外部时钟&#xff09;TIM输出比较示例程序&#xff08;PWM驱动LED呼吸灯&PWM驱动舵机&PWM驱动直流电机&#xff09;TIM输入捕获示例程序&…

基于EasyExcel的数据导入导出(复制可用)

目录 前言&#xff1a; 新建SpringBoot项目&#xff0c;引入下面的依赖 数据导入导出执行原理和思路&#xff1a; 用户端逻辑&#xff1a; 后台开发逻辑&#xff1a; 代码实现 下拉框策略 批注策略 数据读取监听 Excel工具类 创建导入数据模板类 创建数据导出模板 …

LC每日一题 2024/1/25 2859. 计算 K 置位下标对应元素的和

目录 题干 思路 代码 题干 思路 简单的位运算&#xff0c;就是寻找这个数对应的二进制中的1的个数是否与k相同&#xff0c;如果相同&#xff0c;就把这个数加到结果当中 可能涉及到的方法&#xff1a;Integer.bitCount() -->计算出二进制中包含的1的个数 代码 调用Java…

AI引爆算力需求,思腾推出支持大规模深度学习训练的高性能AI服务器

近日人工智能研究公司OpenAI公布了其大型语言模型的最新版本——GPT-4&#xff0c;可10秒钟做出一个网站&#xff0c;60秒做出一个游戏&#xff0c;参加了多种基准考试测试&#xff0c;它的得分高于88%的应试者&#xff1b;随后百度CEO李彦宏宣布正式推出大语言模型“文心一言”…

勒索袭击新方式,提防注册机中注入的勒索病毒!

1 事件概述 近期&#xff0c;用户反馈称自己在使用某款“注册机”软件时候&#xff0c;系统中文件被不行加密。通过对受害用户提供的线索和样本进 行综合分析研判&#xff0c;发现了一款借助破解类工具进行传播的新型勒索软件&#xff0c;其会通过向桌面释放勒索信与收款码图片…

mysql 基础(三)

一、多表设计 数据库设计范式 第一范式(确保每列保持原子性) 第一范式是最基本的范式。如果数据库表中的所有字段值都是不可分解的原子值&#xff0c;就说明该数据库表满足了第一范式。第二范式就是要有主键&#xff0c;要求其他字段都依赖于主键。 没有主键就没有唯一性&…

用ChatGPT写申请文书写进常春藤联盟?

一年前&#xff0c;ChatGPT 的发布引发了教育工作者的恐慌。现在&#xff0c;各大学正值大学申请季&#xff0c;担心学生会利用人工智能工具伪造入学论文。但是&#xff0c;聊天机器人创作的论文足以骗过大学招生顾问吗&#xff1f; ChatGPT简介 ChatGPT&#xff0c;全称聊天生…

【格密码基础】基于LWE问题的密码系统

目录 一. 介绍 二. LWE密码方案简单介绍 三. LWE经典归约 四. LWE性质 五. LWE的鲁棒性 一. 介绍 在2005年&#xff0c;Regev基于LWE问题提出了一个新的公钥密码方案。该方案可实现语义安全&#xff08;semantic security&#xff09;&#xff0c;其中误差率&#xff08;…

【云原生】Docker的镜像创建

目录 1&#xff0e;基于现有镜像创建 &#xff08;1&#xff09;首先启动一个镜像&#xff0c;在容器里做修改 ​编辑&#xff08;2&#xff09;然后将修改后的容器提交为新的镜像&#xff0c;需要使用该容器的 ID 号创建新镜像 实验 2&#xff0e;基于本地模板创建 3&am…

蓝凌OA sysUiExtend.do 任意文件上传漏洞复现

0x01 产品简介 蓝凌核心产品EKP平台定位为新一代数字化生态OA平台,数字化向纵深发展,正加速构建产业互联网,对企业协作能力提出更高要求,蓝凌新一代生态型OA平台能够支撑办公数字化、管理智能化、应用平台化、组织生态化,赋能大中型组织更高效的内外协作与管理,支撑商业…

[docker] Docker的数据卷、数据卷容器,容器互联

一、数据卷&#xff08;容器与宿主机之间数据共享&#xff09; 数据卷是一个供容器使用的特殊目录&#xff0c;位于容器中。可将宿主机的目录挂载到数据卷上&#xff0c;对数据卷的修改操作立刻可见&#xff0c;并且更新数据不会影响镜像&#xff0c;从而实现数据在宿主机与容…

81.网游逆向分析与插件开发-背包的获取-装备栏数据结构的逆向分析

内容参考于&#xff1a;易道云信息技术研究院VIP课 上一个内容&#xff1a;自动化助手显示物品数据-CSDN博客 然后游戏中有弓箭&#xff0c;弓箭有数量&#xff0c;可以作为突破口&#xff0c;也可以使用物品id 获取弓的方式 获取弓箭的方式 然后搜索250 然后搜索出一个 然后…