封装公共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" }]},
}
)

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

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

相关文章

UE4/5Niagara粒子特效之Niagara_Particles官方案例:1.1->1.4

目录 1.1-Simple Sprite Emitter ​编辑 发射器更新 粒子生成 粒子更新 1.2-Simple Sprite Emitter 发射器更新 粒子生成 粒子更新 渲染 1.3-Simple GPU Emitter 属性 发射器更新 粒子生成 粒子更新 1.4-Sprite Facing 发射器更新 粒子生成 粒子更新 通过对官方…

wazuh初探系列二 :Wazuh功能初步探知

目录 介绍 主动响应&#xff1a; 监控日志 "bin"目录用途&#xff1a; 告警信息&#xff1a; etc 目录中包含了以下主要的配置文件&#xff1a; ruleset&#xff1a;自带规则库&#xff0c;建议不改 rules目录: 解码器&#xff1a; 登录日志格式&#xff1a…

财务数据分析模板有哪些,能满足决策吗?

虽然企业的业务经营各有不同&#xff0c;但在财务数据分析上却有着相似的需求与流程&#xff0c;因此财务数据分析是可以形成一套标准化模板的。奥威BI数据可视化工具从多年丰富的BI项目中总结经验&#xff0c;形成一套标准化、系统化的财务数据分析模板&#xff0c;内含资产负…

CentOS中Oracle11g进程有哪些

最近遇到Oracle数据库运行过程实例进程由于某种原因导致中止的问题&#xff0c;专门看了下正常Oracle数据库启动后的进程有哪些&#xff0c;查阅资料了解了下各进程的作用&#xff0c;记录如下。 oracle 3032 1 0 07:36 ? 00:00:00 ora_pmon_orcl oracle …

最优的家电设备交互方式是什么?详解家电设备交互的演进之旅

家电&#xff0c;在人们的日常生活中扮演着不可或缺的角色&#xff0c;也是提升人们幸福感的重要组成部分&#xff0c;那你了解家电的发展史吗&#xff1f; 70年代 结婚流行“四大件”&#xff1a;手表、自行车、缝纫机&#xff0c;收音机&#xff0c;合成“三转一响”。 80年…

git 回滚相关问题

原本用as自带的git执行回滚任务&#xff0c; 但是提交之后发现并没有成功&#xff0c; 后面通过命令行的方式重新回滚并且提交上去&#xff0c;就可以了 说明as的git还是有点小瑕疵&#xff0c;还是命令行最稳妥 相关博文&#xff1a; git代码回滚操作_imkaifan的博客-CSDN博…

网络安全(大厂)面试题

以下为网络安全各个方向涉及的面试题&#xff0c;星数越多代表问题出现的几率越大&#xff0c;祝各位都能找到满意的工作。 注&#xff1a;本套面试题&#xff0c;已整理成pdf文档&#xff0c;但内容还在持续更新中&#xff0c;因为无论如何都不可能覆盖所有的面试问题&#xf…

Springboot 自定义 Mybatis拦截器,实现 动态查询条件SQL自动组装拼接(玩具)

前言 ps&#xff1a;最近在参与3100保卫战&#xff0c;战况很激烈&#xff0c;刚刚打完仗&#xff0c;来更新一下之前写了一半的博客。 该篇针对日常写查询的时候&#xff0c;那些动态条件sql 做个简单的封装&#xff0c;自动生成&#xff08;抛砖引玉&#xff0c;搞个小玩具&a…

Shell语法揭秘:深入探讨常见Linux Shell之间的语法转换

深入探讨常见Linux Shell之间的语法转换 一、引言二、Linux常用Shell&#xff1a;Bash、Zsh、Ksh、Csh、Tcsh和Fish的简介2.1、Bash、Zsh、Ksh、Csh、Tcsh和Fish的特点和用途2.2、语法差异是常见Shell之间的主要区别 三、变量和环境设置的语法差异3.1、变量定义和使用的不同语法…

【算法】活用双指针完成复写零操作

Problem: 1089. 复写零 文章目录 题目解析算法原理分析找到最后一个复写的位置从后往前进行复写操作 代码展示 题目解析 首先我们来分析一下本题的题目意思 可以看到题目中给到了一个数组&#xff0c;意思是让我们将数组中的零元素都复写一遍&#xff0c;然后将其余的元素向后平…

无涯教程-PHP - preg_grep()函数

preg_grep() - 语法 array preg_grep ( string $pattern, array $input [, int $flags] ); 返回由与给定模式匹配的输入数组元素组成的数组。 如果将flag设置为PREG_GREP_INVERT&#xff0c;则此函数返回输入数组中与给定模式不匹配的元素。 preg_grep() - 返回值 返回使用…

odoo安装启动遇到的问题

问题&#xff1a;在第一次加载odoo配置文件的时候&#xff0c;启动失败 方法&#xff1a; 1、先检查odoo.conf的内容&#xff0c;尤其是路径 [options] ; This is the password that allows database operations: ; admin_passwd admin db_host 127.0.0.1 db_port 5432 d…

React(8)

千锋学习视频https://www.bilibili.com/video/BV1dP4y1c7qd?p72&spm_id_frompageDriver&vd_sourcef07a5c4baae42e64ab4bebdd9f3cd1b3 1.React 路由 1.1 什么是路由&#xff1f; 路由是根据不同的 url 地址展示不同的内容或页面。 一个针对React而设计的路由解决方案…

如何使用 Docker Compose 运行 OSS Wordle 克隆

了解如何使用 Docker Compose 在五分钟内运行您自己的流行 Wordle 克隆实例。您将如何部署 Wordle&#xff1f; Wordle在 2021 年底发布后席卷了互联网。对于许多人来说&#xff0c;这仍然是一种早晨的仪式&#xff0c;与一杯咖啡和一天的开始完美搭配。作为一名 DevOps 工程师…

SQL Server 执行报错: “minus“ 附近有语法错误。

sql server 执行带 minus 的语句一直报错&#xff0c;如下图&#xff1a; 找了好久才知道minus是Oracle里面的语法&#xff0c;SQL server 应用 EXCEPT。

存储IO路径:Linux下的“快递之旅”

相信大家都有过网购的经历,当我们在电商平台上浏览心仪的商品并下单时,快递小哥会负责将物品从商家手中送至我们手中。在这个过程中,快递小哥需要经过一系列的流程才能将物品准确送达。同样,在Linux系统中,当用户下发一笔读写操作时,这些数据也需要经过一系列的流程才能最…

【面试】项目经理面试题

文章目录 一、项目管理面试中通常会问到的问题1.项目管理软件工具知识2.做项目计划的技能3.人员管理技能4.沟通技巧5.方法论知识 二、问面试官的问题三. 面试系列推荐 一、项目管理面试中通常会问到的问题 1.项目管理软件工具知识 问题 1: 工期和工作量之间的差异是什么? 答案…

Shell 编程快速入门 之 数学计算和函数基础

目录 1. 求两数之和 整数之和 浮点数之和 2. 计算1-100的和 for...in C风格for循环 while...do until...do while和until的区别 关系运算符 break与continue的区别 3. shell函数基础知识 函数定义 函数名 函数体 参数 返回值 return返回值的含义 return与…

opencv 进阶16-基于FAST特征和BRIEF描述符的ORB(图像匹配)

在计算机视觉领域&#xff0c;从图像中提取和匹配特征的能力对于对象识别、图像拼接和相机定位等任务至关重要。实现这一目标的一种流行方法是 ORB&#xff08;Oriented FAST and Rotated Brief&#xff09;特征检测器和描述符。ORB 由 Ethan Rublee 等人开发&#xff0c;结合了…

基于STC15单片机-LM35-DS8B20温度测量-DS1302计时-proteus仿真-源程序

一、系统方案 本设计采用STC15单片机作为主控器。 DS18B20采集温度值送到液晶1602显示。 DS1302计时&#xff0c;日期送到液晶1602显示。 LM35采集另一路温度值送到数码管显示。 二、硬件设计 原理图如下&#xff1a; 三、单片机软件设计 1、首先是系统初始化 /IO初始化为…