当前位置: 首页 > news >正文

封装公共el-form表单(记录)

1.公共表单组件 

//commonForm.vue
<script>
import {TEXT,SELECT,PASSWORD,TEXTAREA,RADIO,DATE_PICKER
} from '@/conf/uiTypes'
import { deepClone } from '@/utils'
export default {name: 'GFormCreator',props: {config: {  // title/itemstype: Object,required: true}},created() {const { items, cards, rules } = this.config;// 绑定表单验证器thisfor (let key in rules) {rules[key].forEach(r => {// 若该方法是全局方法,第二次bind会失效,因为bind只能绑定一次if (r.validator) {r.validator = r.validator.bind(this)}}) }if (cards) {cards.forEach(card => {this.reactiveFields(card.children);})} else if (items) {this.reactiveFields(items);}},data() {return {ruleForm: {}}},methods: {reactiveFields(items) {console.log(items);if (!items) return;items.forEach((row, rowIndex) => {row.forEach((item, colIndex) => {// this.ruleForm[item.key] = item.value;// Object.defineProperty 对所有key进行响应式,更改后更新// 无法检测到动态添加的key,访问、设置,set/get都无法触发响应式 if (this.ruleForm.hasOwnProperty(item.key)) {// 异常抛出,外部方法没有捕获的画,程序结束throw new Error(`行:${rowIndex + 1}_列${colIndex + 1}` + '已经存在相同的key:' + item.key + ',value:' + item.value)}this.$set(this.ruleForm, item.key, item.value);})});},renderItem(item) {const fd = this.ruleForm;const attrs = item.attrs;switch (item.type) {case TEXT:case PASSWORD:case TEXTAREA:// v-model = @input + :valuereturn <el-input attrs={attrs} v-model={fd[item.key]} type={item.type} ></el-input>case SELECT:return <el-select attrs={attrs} v-model={fd[item.key]}>{item.options.map(opt => {return <el-option value={opt.value} label={opt.label}></el-option>})}</el-select>case DATE_PICKER:return <el-date-pickerattrs={attrs}v-model={fd[item.key]}type="date"placeholder="选择日期"></el-date-picker>case RADIO:  //  {  label:'xxx' radios:[ { attrs:{},label:'xxx' }  ] }return item?.radios?.map(radio => {console.log('radio:', fd[item.key])return <el-radioattrs={radio.attrs}v-model={fd[item.key]} label={radio.label}>{radio.title}</el-radio>})default:return <h2>未匹配{item.type}</h2>}},renderColumns(columns) {return columns.map(col => {return <el-col span={col.colspan}><el-form-item label={col.label} prop={col.key}>{this.renderItem(col)}</el-form-item></el-col>})},renderRows(rows) {return rows.map(rowArr => {return <el-row>{this.renderColumns(rowArr)}</el-row>})},getData() {return deepClone(this.ruleForm)},passData() {// submitthis.$emit('submit', deepClone(this.ruleForm));},// 外部验证// 内部验证返回数据doSubmit() {this.$refs.form.validate(valid => {if (valid) {return this.$emit('submit', deepClone(this.ruleForm));} else {console.log('验证失败');return false;}})},valid(callback) {this.$refs.form.validate(valid => {if (valid) {return callback(deepClone(this.ruleForm))} else {callback(false);console.log('验证失败');return false;}});},reset() {this.$refs.form.resetFields();}, renderCards(cards) {let { renderRows } = this;return cards.map(card => {// 渲染name和children(renderRows) return (<el-card class="box-card" header={card.name}>{card.children && renderRows(card.children)}</el-card >)// 实现方式1// let h = this.$createElement;return h('el-card', { class: 'box-card' }, [h('template', { slot: 'header' }, [h('span', card.name)]),card.children && renderRows(card.children)]);// 实现方式2return (<el-card class="box-card"><template slot="header"><span>{card.name}</span></template>{card.children && renderRows(card.children)}</el-card >);})}},render() {const { title, items, rules, cards } = this.config;const { ruleForm, $scopedSlots: { btn } } = this;return (<div class="form-box">{title && <h2>{title}</h2>} <el-form ref="form" attrs={{ model: ruleForm, }} rules={rules} label-width="80px">{cards ? this.renderCards(cards) : this.renderRows(items)}</el-form> <div class="btn-bow">{btn ? btn({ t: '我是scopod' }) : (<div><el-button type="primary" onClick={e => this.doSubmit()}>提交</el-button><el-button onClick={e => this.reset()}>重置</el-button></div>)}</div> </div>)}
}
</script><style scoped>
.el-input,
.el-select,
.form-box .el-date-editor {width: 100%;
}:deep(.el-card__header) {text-align: left;
}.box-card {margin-bottom: 10px;
}
</style>

(1)声明表单类型 

// conf/uniTypes.js
export const  TEXT = 'text';
export const SELECT = 'select';
export const PASSWORD = 'password';
export const TEXTAREA = 'textarea';
export const RADIO = 'radio';
export const DATE_PICKER= 'datepicker';

 (2)封装深拷贝

// utils/index.jsexport const deepClone = (obj)=>{  // 处理环形对象带来的递归栈内存溢出let cache = new WeakMap(); // 避免强引用var objType = '[object Object]';function innerDeepClone(obj) {// 处理了基本数据类型  undefined null functionif (typeof obj !== 'object' || !obj) {return obj;}// obj不是方法的参数, 改变的this,由于不同类型的对象的type不同,// toString从不同this拿到的就不一样// var type = Object.prototype.toString.call(obj);if (cache.has(obj)){return cache.get(obj);}let tmp;// 处理非对象和数组if (obj instanceof Map) {tmp = new Map();cache.set(obj,tmp);obj.forEach((val, key) => {tmp.set(innerDeepClone(key), innerDeepClone(val))})} else if (obj instanceof Set) {tmp = new Set();cache.set(obj,tmp);obj.forEach(val => {tmp.add(innerDeepClone(val))})} else if (obj instanceof RegExp || obj instanceof Date) {tmp = new obj.constructor(obj);  cache.set(obj,tmp);} else {tmp = new obj.constructor();cache.set(obj,tmp);for (let key in obj) {tmp[key] = innerDeepClone(obj[key]);}}return tmp;}return innerDeepClone(obj)
}

2.使用公共表单组件

<template><div><GFormCreator :config="conf" @submit="createLoan"/><!-- <hr><GFormCreator ref="f2" :config="conf"><template #btn="{t}"><el-button @click="test1">提交{{ t }}</el-button></template></GFormCreator> --></div>
</template><script>
import conf from './loan-input-page'
import { createLoanApi } from '@/api/loan'
export default {methods: {async createLoan(user){let res = await createLoanApi(user);this.$notify.success('添加成功');},test2(data){console.log('数据:',data)},test1() {console.log(this.$refs.f2.getData())}},data() {return {conf}}
}
</script> 
/loan-input-page.js
import {TEXT,SELECT,PASSWORD,TEXTAREA,RADIO,DATE_PICKER
} from '@/conf/uiTypes';//性别
export const sexOptions = [{ value: "man", label: "男" },{ value: "woman", label: "女" }
];
//行业
export const companyOptions = [{ value: "education", label: "教育" },{ value: "finance", label: "金融" }
];
//婚否
export const marriageOptions = [{ value: "married", label: "已婚" },{ value: "unmarried", label: "未婚" }
];
//学历
export const educationOptions = [{ value: "college", label: "大学" },{ value: "highschool", label: "高中" }
];// 优化 => data方法中,默认是会Object.defineProperty => 当触发属性的get/set => 页面的更新export default Object.freeze({cards: [{name: "个人基本信息",children: [[{ label: "姓名", key: "name", type: TEXT },{ label: "出生日期", key: "birthday", type: DATE_PICKER },{label: "性别",key: "sex",type: SELECT,options: sexOptions}],[{ label: "身份证", key: "identity_card", type: TEXT }],[{label: "婚姻状态",key: "marriage",type: "select",options: marriageOptions},{label: "教育程度",key: "education",type: "select",options: educationOptions},{ label: "居住地址", key: "address1", type: TEXT }],[{ label: "户籍地址", key: "address2", type: TEXT },{ label: "居住电话", key: "phone", type: TEXT },{ label: "手机号", key: "mobile_phone", type: TEXT }]].map(row => row.map(item => ({ colspan: 8, ...item })))},{name: "职业信息",children: [[   // element原生属性{ label: "现职公司", key: "company", type: TEXT },{label: "所属行业",attrs: { placeholder: '请选择Green' },key: "trade",type: "select",options: companyOptions},{ label: "职位", key: "position", type: TEXT },{ label: "公司地址", key: "address3", type: TEXT }].map(item => ({ colspan: 6, ...item })),[{ label: "公司类型", key: "company_type", type: TEXT },{ label: "公司邮箱", key: "company_email", type: TEXT },{ label: "公司电话", key: "company_phone", type: TEXT }].map(item => ({ colspan: 8, ...item }))]},{name: "收支情况",children: [[{ label: "收支情况", key: "income", type: TEXT, colspan: 12 }]]},{name: "家庭联系人",children: [[{ label: "关系1", key: "contact", type: TEXT },{ label: "姓名", key: "contact_name", type: TEXT },{ label: "手机", key: "contact_phone", type: TEXT }].map(item => ({ colspan: 12, ...item }))]},{name: "工作证明人",children: [[{ label: "关系2", key: "contact2", colspan: 12, type: TEXT },{ label: "姓名", key: "contact2_name", colspan: 12, type: TEXT },{ label: "手机", key: "contact2_phone", colspan: 12, type: TEXT }],[{ label: "部门", key: "contact2_dep", colspan: 12, type: TEXT },{ label: "职位", key: "contact2_pos", colspan: 12, type: TEXT }],[{ label: "备注", key: "remark", type: "textarea" }]]}],rules: {name: [{ required: true, message: "请输入姓名", trigger: "blur" },{min: 2,max: 5,message: "长度在 2 到 5 个字符",trigger: "blur"}],identity_card: [{ required: true, message: "请输入身份证", trigger: "change" }],birthday: [{type: 'date',required: true,message: "请选择日期",trigger: "change"}],sex: [{ required: true, message: "请选择性别", trigger: "change" }],marriage: [{ required: true, message: "请选择婚姻状态", trigger: "change" }],education: [{ required: true, message: "请选择教育程度", trigger: "change" }],trade: [{ required: true, message: "请选择所属行业", trigger: "change" }],address1: [{ required: true, message: "请输入居住地址", trigger: "blur" }],address2: [{ required: true, message: "请输入户籍地址", trigger: "blur" }],phone: [{ required: true, message: "请输入居住电话", trigger: "blur" }],mobile_phone: [{ required: true, message: "请输入手机号", trigger: "blur" }],company: [{ required: true, message: "请输入现职公司全称", trigger: "blur" }],position: [{ required: true, message: "请输入职位", trigger: "blur" }],address3: [{ required: true, message: "请输入公司地址", trigger: "blur" }],company_type: [{ required: true, message: "请输入公司类型", trigger: "blur" }],company_email: [{ required: true, message: "请输入公司邮箱", trigger: "blur" }],company_phone: [{ required: true, message: "请输入公司电话", trigger: "blur" }],income: [{ required: true, message: "请输入收支情况", trigger: "blur" }],contact: [{ required: true, message: "请输入关系1", trigger: "blur" }],contact_name: [{ required: true, message: "请输入姓名", trigger: "blur" }],contact_phone: [{ required: true, message: "请输入手机", trigger: "blur" }],contact2: [{ required: true, message: "请输入关系2", trigger: "blur" }],contact2_name: [{ required: true, message: "请输入姓名", trigger: "blur" }],contact2_phone: [{ required: true, message: "请输入手机", trigger: "blur" }],contact2_dep: [{ required: true, message: "请输入部门", trigger: "blur" }],contact2_pos: [{ required: true, message: "请输入职位", trigger: "blur" }]},
}
)

相关文章:

封装公共el-form表单(记录)

1.公共表单组件 //commonForm.vue <script> import {TEXT,SELECT,PASSWORD,TEXTAREA,RADIO,DATE_PICKER } from /conf/uiTypes import { deepClone } from /utils export default {name: GFormCreator,props: {config: { // title/itemstype: Object,required: true}}…...

List 分批处理

1.Google Guava <dependency><groupId>com.google.guava</groupId><artifactId>guava</artifactId><version>31.0.1-jre</version></dependency>List<String> tempList Arrays.asList("水星","金星&qu…...

SpringSession

Spring Session 是 Spring 的项目之一。Spring Session 提供了一套创建和管理 Servlet HttpSession 的方案&#xff0c;默认采用外置的 Redis 来存储 Session 数据&#xff0c;以此来解决 Session 共享的 问题。(springsession储存session数据的方式有很多&#xff0c;我们常…...

Python Web 开发之 JWT 简介

在之前的课程中,介绍过 Flask-Login 框架&#xff0c;它是基于 Session 和 Cookie 技术来实现用户授权和验证的&#xff0c;不过 Session 有很多的局限性&#xff0c;这一节介绍一种基于 token 的验证方式 —— JWT (JSON Web Token)&#xff0c;除了对 JWT 的概念讲解之外&…...

科技资讯|荷兰电动自行车丢失将被拒保,苹果Find My可以减少丢失

荷兰最大的自行车协会荷兰皇家旅游俱乐部宣布&#xff0c;将不再为胖胎电动自行车提供保险&#xff0c;因为这种自行车的被盗风险极高。 随着电动自行车的销量飙升&#xff0c;胖胎也变得更受欢迎。但问题是&#xff0c;胖胎电动自行车也成为了自行车盗窃者的首选目标。ANWB …...

debian rules语法

当创建Debian软件包时&#xff0c;debian/rules 文件是非常重要的&#xff0c;它定义了软件包的构建规则。这个文件使用Makefile语法&#xff0c;指导构建、编译和安装软件包。下面将详细地介绍debian/rules文件的语法和常见用法。 基本结构&#xff1a; 一个简单的debian/rul…...

网易2023年Q2财报:营收240亿元,游戏技术跨产业创造数字就业

8月24日&#xff0c;网易发布2023年Q2财报。二季度&#xff0c;网易继续聚焦主营业务&#xff0c;业绩表现稳健&#xff1b;净收入240亿元&#xff0c;非公认会计准则下归属于公司股东的持续经营净利润90亿元&#xff0c;研发投入39亿元&#xff0c;相当于拿出近一半利润投入研…...

Python的Flask框架创建、运行与访问

天行健&#xff0c;君子以自强不息&#xff1b;地势坤&#xff0c;君子以厚德载物。 每个人都有惰性&#xff0c;但不断学习是好好生活的根本&#xff0c;共勉&#xff01; 文章均为学习整理笔记&#xff0c;分享记录为主&#xff0c;如有错误请指正&#xff0c;共同学习进步。…...

Java课题笔记~ 综合案例

3.综合案例 3.1 功能介绍 以上是我们在综合案例要实现的功能。除了对数据的增删改查功能外&#xff0c;还有一些复杂的功能&#xff0c;如 批量删除、分页查询、条件查询 等功能 批量删除 功能&#xff1a;每条数据前都有复选框&#xff0c;当我选中多条数据并点击 批量删除 按…...

Seaborn数据可视化(二)

目录 1.Seaborn风格设置 1.1 主题设置 1.2 轴线设置 1.3 移除轴线 1.4 使用字典传递函数 2.设置绘图元素比例 2.1 设置绘图元素比例paper 2.2 设置绘图元素比例poster 2.3 设置绘图元素比例notebook Seaborn将Matplotlib的参数划分为两个独立的组合&#xff0c;第一组用于…...

HDLBits-Verilog学习记录 | Verilog Language-Basics(1)

文章目录 3.Simple wire4.Four wires5.inverter | Notgate6. And gate7.Nor gate8.Xnorgate 3.Simple wire problem:Create a module with one input and one output that behaves like a wire. module top_module( input in, output out );assign out in;endmodule4.Four w…...

elementui表格嵌套上传文件直传到oss服务器(表单上传)

提示&#xff1a;记录项目中遇到的问题&#xff0c;仅供参考 文章目录 前言一、vue代码二、js接口请求代码 前言 项目需求是在表格中嵌套一个上传图片的功能&#xff0c;并且回显选择的图片和已上传的图片&#xff0c;再通过点击操作列中上传按钮才开始上传&#xff0c;使用的…...

使用navicat来访问doris

访问Doris的UI http:// dorisfe_ip:8030 由于doris是使用mysql协议&#xff0c;因此可以不用任何额外配置就可以使用navicat访问doris。 可以使用MySql客户端来连接Doris FE&#xff0c;也可以使用mysql命令工具连接&#xff0c;因为他是Mysql协议&#xff0c;所以在使用上跟M…...

2023国赛数学建模思路 - 案例:异常检测

文章目录 赛题思路一、简介 -- 关于异常检测异常检测监督学习 二、异常检测算法2. 箱线图分析3. 基于距离/密度4. 基于划分思想 建模资料 赛题思路 &#xff08;赛题出来以后第一时间在CSDN分享&#xff09; https://blog.csdn.net/dc_sinor?typeblog 一、简介 – 关于异常…...

redis实战-缓存三剑客穿透击穿雪崩解决方案

缓存穿透 定义 缓存穿透 &#xff1a;缓存穿透是指客户端请求的数据在缓存中和数据库中都不存在&#xff0c;这样缓存永远不会生效&#xff0c;这些请求都会打到数据库&#xff0c;造成数据库压力&#xff0c;也让缓存没有发挥出应有的作用 解决方案 缓存空对象 当我们客户端…...

Tomcat10安装及配置教程win11

Tomcat10安装及配置教程win11 Tomcat下载链接 Tomcat官网 Tomcat官网地址 https://tomcat.apache.org/ Tomcat的版本列表 点击上图中左侧红框内**Which version?**即可得下图 下载Tomcat 点击上图中左侧红框内红框内tomcat版本即可得下图&#xff0c;下载zip包 解压zip包…...

遗传算法解决TSP问题

一、求解问题概述 1.1 TSP问题 TSP问题是指旅行商问题&#xff08;Traveling Salesman Problem&#xff09;。在TSP问题中&#xff0c;假设有一名旅行商要在给定的一组城市之间进行旅行&#xff0c;每个城市只能被访问一次&#xff0c;并且旅行商必须最终返回出发城市。问题的…...

设计模式-工厂设计模式

核心思想 在简单工厂模式的基础上进一步的抽象化具备更多的可扩展和复用性&#xff0c;增强代码的可读性使添加产品不需要修改原来的代码&#xff0c;满足开闭原则 优缺点 优点 符合单一职责&#xff0c;每个工厂只负责生产对应的产品符合开闭原则&#xff0c;添加产品只需添…...

TM4C123库函数学习(3)---串口中断

前言 &#xff08;1&#xff09;学习本文之前&#xff0c;需要先学习前两篇文章。 &#xff08;2&#xff09;学习本文需要准备好TTL转USB模块。 函数介绍 ROM_GPIOPinConfigure&#xff08;&#xff09; 配置GPIO引脚的复用功能。因为引脚不可能只有一个输出输入作用&#xf…...

opencv 进阶13-Fisherfaces 人脸识别-函数cv2.face.FisherFaceRecognizer_create()

Fisherfaces 人脸识别 PCA 方法是 EigenFaces 方法的核心&#xff0c;它找到了最大化数据总方差特征的线性组合。不可否认&#xff0c;EigenFaces 是一种非常有效的方法&#xff0c;但是它的缺点在于在操作过程中会损失许多特征信息。 因此&#xff0c;在一些情况下&#xff0c…...

Python|GIF 解析与构建(5):手搓截屏和帧率控制

目录 Python&#xff5c;GIF 解析与构建&#xff08;5&#xff09;&#xff1a;手搓截屏和帧率控制 一、引言 二、技术实现&#xff1a;手搓截屏模块 2.1 核心原理 2.2 代码解析&#xff1a;ScreenshotData类 2.2.1 截图函数&#xff1a;capture_screen 三、技术实现&…...

最新SpringBoot+SpringCloud+Nacos微服务框架分享

文章目录 前言一、服务规划二、架构核心1.cloud的pom2.gateway的异常handler3.gateway的filter4、admin的pom5、admin的登录核心 三、code-helper分享总结 前言 最近有个活蛮赶的&#xff0c;根据Excel列的需求预估的工时直接打骨折&#xff0c;不要问我为什么&#xff0c;主要…...

零基础设计模式——行为型模式 - 责任链模式

第四部分&#xff1a;行为型模式 - 责任链模式 (Chain of Responsibility Pattern) 欢迎来到行为型模式的学习&#xff01;行为型模式关注对象之间的职责分配、算法封装和对象间的交互。我们将学习的第一个行为型模式是责任链模式。 核心思想&#xff1a;使多个对象都有机会处…...

聊一聊接口测试的意义有哪些?

目录 一、隔离性 & 早期测试 二、保障系统集成质量 三、验证业务逻辑的核心层 四、提升测试效率与覆盖度 五、系统稳定性的守护者 六、驱动团队协作与契约管理 七、性能与扩展性的前置评估 八、持续交付的核心支撑 接口测试的意义可以从四个维度展开&#xff0c;首…...

全志A40i android7.1 调试信息打印串口由uart0改为uart3

一&#xff0c;概述 1. 目的 将调试信息打印串口由uart0改为uart3。 2. 版本信息 Uboot版本&#xff1a;2014.07&#xff1b; Kernel版本&#xff1a;Linux-3.10&#xff1b; 二&#xff0c;Uboot 1. sys_config.fex改动 使能uart3(TX:PH00 RX:PH01)&#xff0c;并让boo…...

关键领域软件测试的突围之路:如何破解安全与效率的平衡难题

在数字化浪潮席卷全球的今天&#xff0c;软件系统已成为国家关键领域的核心战斗力。不同于普通商业软件&#xff0c;这些承载着国家安全使命的软件系统面临着前所未有的质量挑战——如何在确保绝对安全的前提下&#xff0c;实现高效测试与快速迭代&#xff1f;这一命题正考验着…...

安卓基础(aar)

重新设置java21的环境&#xff0c;临时设置 $env:JAVA_HOME "D:\Android Studio\jbr" 查看当前环境变量 JAVA_HOME 的值 echo $env:JAVA_HOME 构建ARR文件 ./gradlew :private-lib:assembleRelease 目录是这样的&#xff1a; MyApp/ ├── app/ …...

python爬虫——气象数据爬取

一、导入库与全局配置 python 运行 import json import datetime import time import requests from sqlalchemy import create_engine import csv import pandas as pd作用&#xff1a; 引入数据解析、网络请求、时间处理、数据库操作等所需库。requests&#xff1a;发送 …...

华为OD最新机试真题-数组组成的最小数字-OD统一考试(B卷)

题目描述 给定一个整型数组,请从该数组中选择3个元素 组成最小数字并输出 (如果数组长度小于3,则选择数组中所有元素来组成最小数字)。 输入描述 行用半角逗号分割的字符串记录的整型数组,0<数组长度<= 100,0<整数的取值范围<= 10000。 输出描述 由3个元素组成…...

人工智能 - 在Dify、Coze、n8n、FastGPT和RAGFlow之间做出技术选型

在Dify、Coze、n8n、FastGPT和RAGFlow之间做出技术选型。这些平台各有侧重&#xff0c;适用场景差异显著。下面我将从核心功能定位、典型应用场景、真实体验痛点、选型决策关键点进行拆解&#xff0c;并提供具体场景下的推荐方案。 一、核心功能定位速览 平台核心定位技术栈亮…...