Vue3+element-plus复杂表单分组处理

一、为什么表单要分组处理?

  • 方便表单字段的复用:例如,你的表单有十个字段会在很多的表单都会用到,那么表单则需要进行分组进行表单复用;
  • 实现不同角色的表单权限控制:例如一个表单有60个字段,角色A拥有表单前30个的权限,角色B拥有其它30个字段的权限,正常想法,可能会在表单的页面直接获取角色的权限,通过v-if来控制不同字段的权限,这样的话,权限逻辑和表单逻辑就会堆砌在一起,简单一点的表单可能没有太大影响,如果表单逻辑很复杂或者表单字段过多,就会导致代码的臃肿,后期难以维护;若表单进行了分组处理,可以增加一个业务组件来处理权限的逻辑,表单的校验等逻辑则在分组表单中完成。

二、表单分组处理实现思路

  1. 表单字段按业务逻辑进行划分成不同的组,一个组代表一个表单子组件;
  2. 表单子组件实现校验字段的方法,如果有需要重置表单字段需求,则增加表单重置方法;
  3. 增加的校验方法(校验成功则返回子表单所有字段,否则返回null)和表单重置方法,在子组件onMounted钩子中将两个方法传递给业务组件(父组件),业务组件维护两个数组分别存储子表单组件的校验方法和重置表单方法;
  4. 用户点击提交表单或者重置表单时,触发对应维护的数组即可;

三、具体实现代码

3.1 将表单分为两组为例,目录结构如下:
在这里插入图片描述
在这里插入图片描述

效果图如下:

请添加图片描述

3.2 ComplexForm.vue业务组件代码如下:

<script setup lang="ts">
import FormItemA from "@/views/component/complex-form/FormItemA.vue";
import FormItemB from "@/views/component/complex-form/FormItemB.vue";
import { reactive, provide, ref, onMounted } from "vue";defineOptions({name: "ComplexForm"
});const formData = ref({});
// 向子组件注入表单的初始化的值或者回填的值,一般是编辑表单的时候需要传递
provide("defaultFormData", formData);const getFormData = () => {formData.value = {name: "Hello",region: "shanghai",count: "5",date1: "",date2: "",delivery: false,type: [],resource: "",desc: "hello world"};
};
onMounted(() => {});
// 将子组件表单的参数添加到formData中汇总
const addParamsToFormData = (params: any) => {Object.assign(formData.value, params);
};
const formEventList = reactive([]);
// 存储子组件的表单验证方法,在提交时统一调用
const addEventToFormEventList = (event: Function) => {formEventList.push(event);
};
const submitHandler = () => {let successFlag = true;console.log("formEventList=", formEventList);formEventList.forEach((func, index, list) => {// 执行子组件的方法(表单验证+触发add-params添加参数)func().then(res => {if (!res) {// 如果表单存在一个不满足,则设置标识为false,后续根据这个标识来确定是否可以提交表单successFlag = false;} else {// 表单验证通过后,添加参数到formDataaddParamsToFormData(res);}// 执行最后一个表单验证并且通过后,提交表单处理if (index === list.length - 1 && successFlag) {console.log("表单验证通过,提交表单");}}).catch(err => {console.log("返回错误", err);});});
};const formResetEvent = reactive([]);
//  存储子组件的表单重置方法,在重置时统一调用
const addFormResetEvent = func => {formResetEvent.push(func);
};
const resetForm = () => {formResetEvent.forEach(func => {func();});
};
</script><template><div>{{ formData }}</div><FormItemA@add-submit-event="addEventToFormEventList"@add-reset-event="addFormResetEvent"/><FormItemB@add-submit-event="addEventToFormEventList"@add-reset-event="addFormResetEvent"/><el-button type="primary" @click="submitHandler">表单提交</el-button><el-button @click="resetForm">重置表单</el-button><el-button @click="getFormData">模拟接口请求表单回填数据</el-button>
</template><style scoped lang="scss"></style>

3.2 FormItemA.vue 子组件代码如下:

<script lang="ts" setup>
import {reactive,ref,defineEmits,onMounted,inject,watch,nextTick
} from "vue";
import type { FormInstance, FormRules } from "element-plus";interface RuleForm {name: string;region: string;count: string;
}interface Emits {(e: "add-submit-event", event: Function): void;(e: "add-reset-event", event: Function): void;
}
const emits = defineEmits<Emits>();// 接受注入的默认表单数据(表单回填)
const defaultFormData = inject("defaultFormData");onMounted(() => {// 将当前表单验证方法传递给父组件维护的数组,父组件点击提交时,统一遍历数组进行表单验证emits("add-submit-event", submitForm);emits("add-reset-event", resetForm);
});const setDefaultFormData = (ruleForm, sourceForm) => {console.log("666666--sourceForm", sourceForm);for (const key in ruleForm) {if (Object.prototype.hasOwnProperty.call(sourceForm, key)) {ruleForm[key] = JSON.parse(JSON.stringify(sourceForm[key]));}}
};watch(() => defaultFormData.value,() => {console.log("watch监听");// 回填表单数据时,需要加nextTick,否则ruleFormRef.value.resetFields()初始化表单时,会初始化为赋值后的表单数据(无法达到真正初始化表单为空值)nextTick(() => {setDefaultFormData(ruleForm, defaultFormData.value);});},{immediate: true}
);const formSize = ref("default");
const ruleFormRef = ref<FormInstance>();
const ruleForm = reactive<RuleForm>({name: "Hello",region: "",count: ""
});const rules = reactive<FormRules<RuleForm>>({name: [{ required: true, message: "Please input Activity name", trigger: "blur" },{ min: 3, max: 5, message: "Length should be 3 to 5", trigger: "blur" }],region: [{required: true,message: "Please select Activity zone",trigger: "change"}],count: [{required: true,message: "Please select Activity count",trigger: "change"}]
});// 单个表单提交,校验通过则返回表单的字段,校验失败则返回null
const submitForm = () => {return new Promise((resolve, reject) => {if (!ruleFormRef.value) return resolve(null);ruleFormRef.value.validate((valid, fields) => {if (valid) {console.log("formItemA---submit!");resolve(ruleForm);} else {resolve(null);}});});
};const resetForm = () => {if (!ruleFormRef.value) return;ruleFormRef.value.resetFields();
};const options = Array.from({ length: 10000 }).map((_, idx) => ({value: `${idx + 1}`,label: `${idx + 1}`
}));
</script><template><el-formref="ruleFormRef":model="ruleForm":rules="rules"label-width="120px"class="demo-ruleForm":size="formSize"status-icon><el-form-item label="Activity name" prop="name"><el-input v-model="ruleForm.name" /></el-form-item><el-form-item label="Activity zone" prop="region"><el-select v-model="ruleForm.region" placeholder="Activity zone"><el-option label="Zone one" value="shanghai" /><el-option label="Zone two" value="beijing" /></el-select></el-form-item><el-form-item label="Activity count" prop="count"><el-select-v2v-model="ruleForm.count"placeholder="Activity count":options="options"/></el-form-item></el-form>
</template>

3.3 FormItemB.vue 子组件代码如下

<script lang="ts" setup>
import {reactive,ref,defineEmits,onMounted,watch,nextTick,inject
} from "vue";
import type { FormInstance, FormRules } from "element-plus";interface RuleForm {date1: string;date2: string;delivery: boolean;type: string[];resource: string;desc: string;
}interface Emits {(e: "add-submit-event", event: Function): void;(e: "add-reset-event", event: Function): void;
}
const emits = defineEmits<Emits>();// 接受注入的默认表单数据(表单回填)
const defaultFormData = inject("defaultFormData");onMounted(() => {// 将当前表单验证方法传递给父组件维护的数组,父组件点击提交时,统一遍历数组进行表单验证emits("add-submit-event", submitForm);emits("add-reset-event", resetForm);
});const setDefaultFormData = (ruleForm, sourceForm) => {console.log("666666--sourceForm", sourceForm);for (const key in ruleForm) {if (Object.prototype.hasOwnProperty.call(sourceForm, key)) {ruleForm[key] = JSON.parse(JSON.stringify(sourceForm[key]));}}
};watch(() => defaultFormData.value,() => {console.log("watch监听");// 回填表单数据时,需要加nextTick,否则ruleFormRef.value.resetFields()初始化表单时,会初始化为赋值后的表单数据(无法达到真正初始化表单为空值)nextTick(() => {setDefaultFormData(ruleForm, defaultFormData.value);});},{immediate: true}
);const formSize = ref("default");
const ruleFormRef = ref<FormInstance>();
const ruleForm = reactive<RuleForm>({date1: "",date2: "",delivery: false,type: [],resource: "",desc: ""
});const rules = reactive<FormRules<RuleForm>>({date1: [{type: "date",required: true,message: "Please pick a date",trigger: "change"}],date2: [{type: "date",required: true,message: "Please pick a time",trigger: "change"}],type: [{type: "array",required: true,message: "Please select at least one activity type",trigger: "change"}],resource: [{required: true,message: "Please select activity resource",trigger: "change"}],desc: [{ required: true, message: "Please input activity form", trigger: "blur" }]
});const submitForm = () => {return new Promise((resolve, reject) => {if (!ruleFormRef.value) return resolve(null);ruleFormRef.value.validate((valid, fields) => {if (valid) {console.log("formItemB---submit!");resolve(ruleForm);} else {// console.log("error submit!", fields);resolve(null);}});});
};const resetForm = () => {if (!ruleFormRef.value) return;ruleFormRef.value.resetFields();
};
</script><template><el-formref="ruleFormRef":model="ruleForm":rules="rules"label-width="120px"class="demo-ruleForm":size="formSize"status-icon><el-form-item label="Activity time" required><el-col :span="11"><el-form-item prop="date1"><el-date-pickerv-model="ruleForm.date1"type="date"label="Pick a date"placeholder="Pick a date"style="width: 100%"/></el-form-item></el-col><el-col class="text-center" :span="2"><span class="text-gray-500">-</span></el-col><el-col :span="11"><el-form-item prop="date2"><el-time-pickerv-model="ruleForm.date2"label="Pick a time"placeholder="Pick a time"style="width: 100%"/></el-form-item></el-col></el-form-item><el-form-item label="Instant delivery" prop="delivery"><el-switch v-model="ruleForm.delivery" /></el-form-item><el-form-item label="Activity type" prop="type"><el-checkbox-group v-model="ruleForm.type"><el-checkbox label="Online activities" name="type" /><el-checkbox label="Promotion activities" name="type" /><el-checkbox label="Offline activities" name="type" /><el-checkbox label="Simple brand exposure" name="type" /></el-checkbox-group></el-form-item><el-form-item label="Resources" prop="resource"><el-radio-group v-model="ruleForm.resource"><el-radio label="Sponsorship" /><el-radio label="Venue" /></el-radio-group></el-form-item><el-form-item label="Activity form" prop="desc"><el-input v-model="ruleForm.desc" type="textarea" /></el-form-item></el-form>
</template>

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

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

相关文章

VisualStudio 2022的安装

1.IDE 推荐最新版VisualStudio2022&#xff0c;功能十分强大&#xff0c;社区版就够用了。下载地址 2.安装 工作负载选择桌面开发&#xff0c;Web开发可以暂时不选中&#xff08;大部分都用不到&#xff09;。 单个组件选中NET 6.0和NET Frameword4.6.1 也就可以了。 后面安…

14-RPC-自研微服务框架

RPC RPC 框架是分布式领域核心组件&#xff0c;也是微服务的基础。 RPC &#xff08;Remote Procedure Call&#xff09;全称是远程过程调用&#xff0c;相对于本地方法调用&#xff0c;在同一内存空间可以直接通过方法栈实现调用&#xff0c;远程调用则跨了不同的服务终端&a…

汽车零部件制造中的信息抽取技术:提升效率与质量的关键

一、引言 在汽车制造业中&#xff0c;零部件的生产是整个制造流程的关键一环。这些零部件&#xff0c;包括但不限于制动系统、转向系统和传动系统&#xff0c;是确保汽车安全、可靠运行的基础。为了满足现代汽车工业对效率和质量的严格要求&#xff0c;制造商们纷纷投入到高度…

Jetpack Compose: Hello Android

Jetpack Compose 是一个现代化的工具包&#xff0c;用于使用声明式方法构建原生 Android UI。在本博文中&#xff0c;我们将深入了解一个基本的 “Hello Android” 示例&#xff0c;以帮助您开始使用 Jetpack Compose。我们将探讨所提供代码片段中使用的函数和注解。 入门 在…

软件测试--性能测试工具JMeter

软件测试--性能测试工具JMeter 主流性能测试工具1.主流性能测试工具Loadrunner和Jmeter对比 —— 相同点2.主流性能测试工具Loadrunner和Jmeter对比 —— 不同点JMeter基本使用JMeter环境搭建1.安装JDK:2.安装Jmeter:3.注意点:JMeter功能概要1. JMeter文件目录介绍1.1 bin目…

瑞_23种设计模式_享元模式

文章目录 1 享元模式&#xff08;Flyweight Pattern&#xff09;1.1 介绍1.2 概述1.3 享元模式的结构1.4 享元模式的优缺点1.5 享元模式的使用场景 2 案例一2.1 需求2.2 代码实现 3 案例二3.1 需求3.2 代码实现 4 JDK源码解析&#xff08;Integer类&#xff09; &#x1f64a; …

13-Java代理模式 ( Proxy Pattern )

Java代理模式 摘要实现范例 代理模式&#xff08;Proxy Pattern&#xff09;使用一个类代表另一个类的功能 代理模式创建具有现有对象的对象&#xff0c;以便向外界提供功能接口 代理模式属于结构型模式 摘要 1. 意图 为其他对象提供一种代理以控制对这个对象的访问2. 主…

力扣206反转链表

206.反转链表 力扣题目链接(opens new window) 题意&#xff1a;反转一个单链表。 示例: 输入: 1->2->3->4->5->NULL 输出: 5->4->3->2->1->NULL 1&#xff0c;双指针 2&#xff0c;递归。递归参考双指针更容易写&#xff0c; 为什么不用头插…

3.1_2024ctf青少年比赛部分web题

php后门 根据x-powered-by知道php的版本 该版本存在漏洞&#xff1a; PHP 8.1.0-dev 开发版本后门 根据报错信息&#xff0c;进行提示&#xff0c;前 GET / HTTP/1.1 Host: challenge.qsnctf.com:31639 User-Agentt:12345678system(cat /flag);var_dump(2*3);zerodium12345678…

【小白学机器学习6】真实值,观测值,拟合值,以及数据的误差的评价:集中趋势,离散度,形状等

目录 1 世界上有哪几种值&#xff1f;只有3种值 1.1 真值/真实值/理想值/主观值&#xff08;形而上学世界里&#xff09; 1.2 实际值/现实值/观测值/样本值&#xff08;看到的/记录下来的&#xff09; 1.3 拟合值/预测值&#xff08;算出来的&#xff09; 2 对数据的各种…

springboot项目单纯使用nacos注册中心功能

Spring Boot 项目完全可以单独使用 Nacos 作为注册中心。Nacos 是一个更易于构建云原生应用的动态服务发现、配置管理和服务管理平台。它支持服务的注册与发现&#xff0c;能够与 Spring Boot 应用无缝集成&#xff0c;为微服务架构提供了强大的支持。 在使用 Nacos 作为注册中…

Python实现DMI工具判断信号:股票技术分析的工具系列(3)

Python实现DMI工具判断信号&#xff1a;股票技术分析的工具系列&#xff08;3&#xff09; 介绍算法解释 代码rolling函数介绍完整代码 介绍 先看看官方介绍&#xff1a; DMI (趋向指标&#xff09; 用法 1.PDI线从下向上突破MDI线&#xff0c;显示有新多头进场&#xff0c;为…

BUUCTF---[BJDCTF2020]藏藏藏1

1.题目描述 2.下载附件&#xff0c;解压之后是一张图片和一个文本 3.把图片放在winhex,发现图片里面包含压缩包 4.在kali中使用binwalk查看&#xff0c;然后使用foremost分离&#xff0c;在使用tree查看分离出来的文件&#xff0c;最后将zip文件使用unzip进行解压。步骤如下 5.…

pdf编辑软件哪个好用?5款PDF编辑器分享

pdf编辑软件哪个好用&#xff1f;PDF编辑软件在现代办公和学术研究中发挥着举足轻重的作用&#xff0c;它们不仅具备基础的编辑和修改功能&#xff0c;还能够支持多种注释工具&#xff0c;帮助我们高效地管理和整理PDF文件。无论是需要调整文档布局、添加文本或图像&#xff0c…

C++ 前缀和

目录 例1 例2 例3 例4 例5 例6 例7 例8 例1 DP34 【模板】前缀和 分析&#xff1a;dp和arr的大小并不是固定的&#xff0c;就是有没有偏移量&#xff0c;这里的n是从1开始&#xff0c;不如直接放到下标1处&#xff0c;在最后的减法时&#xff0c;如果用第一个参考代码会…

rtt的io设备框架面向对象学习-touch设备

目录 1.触摸设备基类2.触摸设备基类的子类3.初始化/构造流程3.1设备驱动层3.2 设备驱动框架层3.3 io设备管理层 4.总结5.使用5.1实例 1.触摸设备基类 此层处于设备驱动框架层。此层的类是抽象类。 在/ components / drivers / include / drivers /touch.h定义了如下touch设备…

Ai学社致力于Ai视觉设计和AI绘画

Ai学社来啦&#xff01;致力于短时间搞定Ai视觉设计、AI绘画。 遍知首席Ai讲师&#xff0c;教大家如何利用Ai迅速提升工作效率&#xff0c;升职加xin&#xff01;目前申请对ai感兴趣的均可以参加&#xff01;免费报名。 招生人数&#xff1a;本批次至少招募100名。招生时间&…

LeetCode-02

225. 用队列实现栈 用两个队列实现栈的功能&#xff0c;思路如下&#xff1a; 往空队列中放新元素把非空队列中的元素依次放入刚才添加了新元素的队列&#xff0c;直到非空队列变为空队列 class MyStack(object):def __init__(self):self.queue1 []self.queue2 []def push(…

【教程】Kotlin语言学习笔记(四)——方法(持续更新)

写在前面&#xff1a; 如果文章对你有帮助&#xff0c;记得点赞关注加收藏一波&#xff0c;利于以后需要的时候复习&#xff0c;多谢支持&#xff01; 【Kotlin语言学习】系列文章 第一章 《认识Kotlin》 第二章 《数据类型》 第三章 《数据容器》 第四章 《方法》 文章目录 【…

突发,Anthropic推出突破性Claude 3系列模型,性能超越GPT-4

&#x1f989; AI新闻 &#x1f680; 突发&#xff0c;Anthropic推出突破性Claude 3系列模型 摘要&#xff1a;人工智能创业公司Anthropic宣布推出其Claude 3系列大型语言模型&#xff0c;该系列包括Claude 3 Haiku、Claude 3 Sonnet和Claude 3 Opus三个子模型&#xff0c;旨…