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,一经查实,立即删除!

相关文章

c# 加载图片到img控件

1、加载函数 private Image LoadPicFromPath(string fileName) { Image img null; if (System.IO.File.Exists(fileName)) { Image img Image.FromFile(fileName); System.IO.MemoryStream mStream new Syste…

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;制造商们纷纷投入到高度…

HTML <script>元素的10个属性

将javascrip插入HTML的主要方法是使用<script>元素&#xff0c;这个元素是网景公司&#xff08;Netscape&#xff09;创造出来的&#xff0c;script 元素所属类型因其用法而异。位于 head 元素中的 script 元素属于元数据元素&#xff0c;位于其他元素&#xff08;如 bod…

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; …

如何保证某个程序系统内只运行一个,保证原子性

GetMapping("/startETL") // Idempotent(expireTime 90, info "请勿90秒内连续点击")public R getGaugeTestData6() {log.info("start ETL");//redis设置t_data_load_record 值为2bladeRedis.set("t_data_load_record_type", 2);Str…

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; 为什么不用头插…

如何开通 chatGPT4 会员

如何开通 chatGPT4 会员 你是否对最新的人工智能技术充满好奇&#xff1f;想要体验OpenAI的最新成果&#xff0c;ChatGPT-4&#xff1f;现在&#xff0c;通过https://bewildcard.com/i/XUE16 这个链接注册WildCard&#xff0c;你可以轻松实现这一切&#xff01; 详细教程Wild…

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 对数据的各种…

C语言利用函数创建链表,修改链表(插入,删除,添加),指针函数的返回

这段代码是一个简单的链表操作程序&#xff0c;包括创建节点、在链表末尾添加节点、在指定位置插入节点和删除指定位置的节点。以下是详细的注释&#xff1a; #include<stdio.h> #include<stdlib.h>// 定义链表节点结构体 struct listnode{int i; // 节点存储的整…

TDengine 签约树根互联,应对“高基数”难题

近日&#xff0c;树根互联与涛思数据达成签约合作&#xff0c;共同推动智能制造领域的建设。作为一家处于高速发展期的工业互联网企业&#xff0c;树根互联将新一代信息技术与制造业深度融合&#xff0c;开发了以自主可控的工业互联网操作系统为核心的工业互联网平台——根云平…

【HTML】HTML标签实例学习笔记(待更新)-黑马程序员

【HTML】HTML标签实例学习笔记&#xff08;待更新&#xff09;-黑马程序员 成对出现的标签 标签一般都是成对出现&#xff0c;标签之间的关系有包含关系和并列关系两种。 像 <head></head>为双标签&#xff0c;<br/>为单标签 单标签很少 大多数都为双标签。…

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;为…

系统架构29 - 架构风格补充(下)

面向服务架构风格 关键目标关键技术实现方式WEB Service服务注册表企业服务总线ESB特点&#xff1a; SOA是一种 粗粒度、松耦合服务架构&#xff0c;服务之间通过简单、精确定义接口进行通信&#xff0c;不涉及底层编程接口和通信模型。 在SOA中&#xff0c; 服务是一种为了满…