开源表单设计器vue-form-design自动化校验实现原理

未命名.gif

表单校验可以改善用户体验和减轻服务器的压力, 而动态配置表单校验能极大的提高动态表单的扩展性、灵活性, 满足多样性、差异化需求

目标

👌,首先我们简要说下要实现的目标功能:

  • 具有基础的表单验证功能
  • 提供一些内置验证规则
  • 提供对外开放的能力

这样就能直接通过配置的形式无代码来表单校验

背景

开源库 vue-form-design基于 Vue3 的可视化表单设计器,拖拽式操作让你快速构建一个表单, 让表单开发简单而高效。

低代码表单设计器, 可以通过拖拽的形式生成 n 种不同类型的表单, 这样的表单如何校验数据的准确性?

就需要用到 element-plus 提供的表单校验相关规则, 并且该规则是一个对象, 那我们是不是可以配置 json 来进行校验?

在开发表单设计器初期, 确实是通过 json 配置的形式进行表单校验, 但是这种方法有几大缺陷

  • 局限于 element-plus 提供出来的校验方式, 如必填, 数字校验, 长度校验等
  • 保存动态表单配置时会转成 json 字符串, 如果使用 element-ui 自定义校验函数时,会转换成空 (就算能使用函数的 toString 方法转成字符串, 但校验函数的代码提示不好, 不能自定义参数等)
  • 入门门槛高, 需了解 element-plus 校验方式, 需要一定的基础
  • 流程复杂, 不能通过下拉框枚举出常见校验直接使用
  • 动态表单, 顾名思义, 可以通过表单配置的形式来校验输入的准确性, 但 json 配置的方式不支持

从以上几大缺陷可知, 使用 json 校验方式的扩展性, 可维护性, 便捷性, 灵活性都没有, 所以才需要重新设计动态表单的校验方式

技术

组件库使用的是element-plus, 所以相关表单校验的设计要符合element-plus提供的规则

如以下规则:

{"rules": {"name": [{ "required": true, "message": "请输入活动名称", "trigger": "blur" },{ "min": 3, "max": 5, "message": "长度在 3 到 5 个字符", "trigger": "blur" }],"region": [{ "required": true, "message": "请选择活动区域", "trigger": "change" }]}
}

自定义校验函数规则:

var validatePass = (rule, value, callback) => {if (value === "") {callback(new Error("请输入密码"));} else {if (this.ruleForm.checkPass !== "") {this.$refs.ruleForm.validateField("checkPass");}callback();}
};

为了提升扩展性, 可以通过编写自定义校验函数的形式进行校验, 涉及到代码开发, 所以需要一个可提示、可编写注释的开源编辑器codemirror

CodeMirror 是基于 js 的源代码编辑器组件,它支持 javascript 等多种高级语言,tampermonkey 内置的代码编辑器就是基于它。它的按键组合方式兼容 vim,emacs 等,调用者还可自定义’自动完成’的列表窗口,自由度极高,相当成熟。

使用

import { basicSetup } from "codemirror";
import VueCodemirror from "vue-codemirror";
import { javascript } from "@codemirror/lang-javascript";// 全局注册
app.use(VueCodemirror, {autofocus: true,disabled: false,indentWithTab: true,tabSize: 2,placeholder: "Code goes here...",extensions: [basicSetup, javascript()],
});

以上是可以编写 javascript 相关代码, 如果我们要编写 css, json 呢? 正好在该库也使用到

import { json } from "@codemirror/lang-json";
export default {setup() {const extensions = [json()];return {extensions,};},
};

template

<codemirror v-model="code" placeholder="Code goes here..." mode="text/json" :style="{ height: '400px' }" :extensions="extensions" :autofocus="true" :indent-with-tab="true" :tab-size="2" />

通过以上代码, 就可以在项目中使用 codemirror 来编写 javascript 代码

架构设计

通过以上两种技术, 我相信大家都知道 element-plus 两种校验方式

那如何解决几大缺陷?

我是如何做的? 以下三种方式进行解决

枚举校验

把常见的、已知的校验规则枚举出来, 直接通过文件引用的方式遍历出校验列表进行选择(最好是维护到后台里面, 通过接口获取, 这样方便增删改查)

如:

// 数字校验规则
const validateNumber = `(rule, value, callback) => {console.log(rule);if (value === "" || value == null) {callback(new Error("请输入"));} else if (!/^[0-9]*$/.test(value)) {callback(new Error("必须为数字"));}callback();
}`;
// 数字校验规则(小数点保留两位)
const validateNumberD2 = `(rule, value, callback) => {if (value === "" || value == null) {callback(new Error("请输入"));} else if (!/^([1-9]+[\d]*(.[0-9]{1,2})?)$/.test(value)) {callback(new Error("必须为数字,且小数点最多两位"));}callback();}`;
const ruleList = [{label: "数字校验规则",validator: validateNumber,},{label: "数字校验规则(小数点保留两位)",validator: validateNumberD2,},
];
export default ruleList;

这样就可以通过下拉框的形式选择需要使用的校验方式

表单自定义配置

把 element-plus 校验规则进行总结, 归纳出所有组合类型, 通过表单配置的形式选择

企业微信截图_5f558adb-7b07-4ef1-bcd5-63d6e1e072cb.png

这样就可以把校验规则进行可视化配置, 直观配置需要的校验规则, 学习成本低

同时校验规则表单列表使用到了动态表单组件(上图), 即 vue-form-design 暴露出来的两个组件其一(渲染表单组件和配置表单组件)

自定义校验函数

上文可知, 自定义校验函数使用到了 CodeMirror, 这样的话就可以编写代码

企业微信截图_0eaa5d09-a226-4cd1-bac7-163c661f9180.png

上图可知, 包括两个配置

  • 函数触发事件配置, blur 还是 change
  • 校验函数配置

该配置只写函数体, 如果整个函数可配, 可能导致参数使用错误, 并且把参数位置写死, 并和 element-plus 保持一致,
这样后期好处理, 降低配置错误率.并且把每个参数的作用列出来, 方便开发. 同时在 element-plus 固有的参数基础上, 新增了第四个参数, 表示当前表单配置数据,
方便基于其他表单数据作为校验判断的基础

使用场景如:

企业微信截图_1e2b9915-b9d1-49d9-8772-a9e091446935.png

假设有两个表单如图, 一个是开关表单, 一个是校验表单

文本表单要求开关表单配置为 true 才校验通过, 否则不通过

则配置自定义函数

企业微信截图_d74be027-1e9d-468d-8767-c3e0adecf0ad.png
这样就使用到了第四个参数, 即拿到当前表单列表页数据{ceshi: true, verify: ""}, 进行校验

通过以上方法, 极大的提高了表单校验的扩展性, 灵活性

使用 codemirror 返回的函数体为一个字符串, 这种数据结构就能方便存储和进行各种处理, 如下

{"rule": [{"type": "func","title": "自定义函数规则","value": {"trigger": "blur","func": "if(mainData.ceshi){callback()}else{\n  callback(new Error(\"请变更为false\"));\n}\n"}}]
}

通过以上三种方法就能解决使用 json 配置的所有缺陷

下面的 json 是 element-plus 的校验规则例子, 大家发现了什么规则? 是不是字段的校验规则的数据结构是数组, 代表可配置多个校验规则

{"rules": {"name": [{ "required": true, "message": "请输入活动名称", "trigger": "blur" },{ "min": 3, "max": 5, "message": "长度在 3 到 5 个字符", "trigger": "blur" }]}
}

所以为了和 element-plus 保持一致, 我们可以使用以上三个方法动态遍历设置校验规则

运用

企业微信截图_85ec9275-fffc-4e38-9b32-63669c634aa8.png

如图, 在 vue-form-design 中可动态配置校验方式(自定义枚举、自定义校验函数、高级模式), 并按对应校验方式配置校验规则

一个表单最后生成的数据结构如下:

[{"ControlType": "Text","nameCn": "文本框","id": "QGR69RscPmjnFqHW7JeMB","layout": false,"data": {"fieldName": "Text_N-A6Ft1FUd8NJyrWN3LL2","label": "标签名称","tip": "","placeholder": "","showRule": "{}","required": false,"rule": [{"type": "enum","title": "自定义枚举","value": "(rule, value, callback) => {\n    if (value === \"\" || value == null) {\n      callback(new Error(\"请输入\"));\n    } else if (!/^1(?:3d|4[4-9]|5[0-35-9]|6[67]|7[013-8]|8d|9d)d{8}$/.test(value)) {\n      callback(new Error(\"请输入正确的值\"));\n    }\n    callback();\n  }"},{"type": "func","title": "自定义函数规则","value": {"trigger": "blur","func": "callback()"}},{"type": "high","title": "高级模式","value": {"message": "必填","trigger": "change","required": true,"ruleType": "1"}}],"default": "","csslist": []}}
]

最后渲染表单组件时再处理每个表单的校验规则, 拼接成 element-plus 要求的数据接口即可.

如上数据结构,最后转换为如下 校验规则 json:

{"rules": {"Text_N-A6Ft1FUd8NJyrWN3LL2": [// ...]}
}

校验实现

上文可知, 三种校验方式(自定义枚举、自定义校验函数、高级模式), 目的是转换为 element-plus 要求的规则

只要我们把配置的规则进行转换就能实现校验

function getFormListRules(rules: any[]) {const result: any[] = [];if (Array.isArray(rules) && rules && rules.length > 0) {rules.forEach((item) => {if (item.type == "enum") {// 自定义枚举 上文可知我们枚举出来的是函数字符串, 使用eval执行返回函数const func = eval(`(${item.value})`);result.push({validator: func,trigger: "blur",});} else if (item.type == "func") {// 自定义函数校验 配置的是函数体 所以我们需要自己拼接出函数, 第四个参数需要通过使用默认参数的形式进行传参(利用到了闭包), 否则element-plus底层获取不到当前表单数据const mainData = props.formResult;const func = eval(`((rule, value, callback, mainData = mainData) => {${item.value.func}})`);result.push({validator: func,trigger: "blur",});} else if (item.type == "high") {//  高级模式 是通过表单配置出element-plus支持的数据, 所以不做特殊处理, 因为数字校验min, max使用表单配置校验不成功, 所有兜底使用了函数校验if (item.value.ruleType == 5) {result.push({validator: eval(item.value.validor),trigger: item.value.trigger,});return;}result.push(item.value);}});}return result;
}
const rules = ref({});
function getRules(item) {let rule = [];if (item.data.required) {rule.push({required: true,message: "请输入" + item.data.label,trigger: "blur",});}if (typeof item.data.rule == "string") {rule = rule.concat(proxy.$Flex.tryParseJson(item.data.rule));} else {rule = rule.concat(getFormListRules(item.data.rule));}// 特殊的jsoneditor表单要单独处理if (item.data.json) {rule.push(...proxy.$Flex.getJsonValidate());}rules.value[item.data.fieldName] = rule;
}

template 上使用

<el-form ref="ruleForm" :model="formResult" :rules="rules"> </el-form>

最后就能转换出 element-plus 用到校验数据格式

总结

三种校验方案都是基于 element-plus 提供的规则, 合理利用和发掘, 对其进行封装设计, 能在程序上极大提升配置效率, 降低门槛

自定义函数校验还是有一定的缺陷, 如自定义代码有缺陷或者抛错, 外层未进行兜底等, 后期会进行解决

github 地址

预览

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

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

相关文章

用OceanBase binlog service 轻松进行数据回滚

背景 在日常的数据库运维过程中&#xff0c;难免会遭遇数据误操作的情形&#xff0c;比如因疏忽而执行了非预期的delete或update操作&#xff0c;这时就需要进行数据回滚。如果在OceanBase中启用了回收站功能&#xff0c;并设置了合适的undo_retention&#xff0c;那么我们可以…

jmx_prometheus_javaagent-0.19.0.jar+Prometheus+Grafana 监控Tongweb嵌入式(by lqw)

文章目录 1.思路2.部署准备3.应用jar包修改配置和导入tw嵌入式的依赖&#xff08;参考&#xff09;4.Prometheus部署5.Prometheus配置6.安装和配置Grafana 1.思路 Tongweb嵌入式最终是把依赖打入到java应用&#xff08;也就是jar包里&#xff09;&#xff0c;然后启动jar包进行…

单片机LED灯闪烁

延时函数计算&#xff08;相关代码生成&#xff09;&#xff1a; #include "reg52.h" #include <INTRINS.H> void Delay500ms() //11.0592MHz {unsigned char i, j, k;_nop_();_nop_();i 22;j 3;k 227;do{do{while (--k);} while (--j);} while (--i); }vo…

让扣你代码的人电脑关机-js反爬

文案 让扣你代码的人电脑关机&#xff0c;赶紧学起来。众所周知。浏览器中无法导入模块&#xff0c;会报错。nodejs中可以导入模块。那么我们可以在导入语句后加入整蛊代码。在捕获异常后执行正常的代码。那么代码在浏览器中就会正常执行&#xff0c;而当你在本地环境中执行的…

Docker常用命令!!!

一、docker基础命令 1、启动docker systemctl start docker 2、关闭docker systemctl stop docker 3、重启docker systemctl restart docker 4、docker设置随服务启动而自启动 systemctl enable docker 5、查看docker 运行状态 systemctl status docker 6、查看docker 版本号信…

Microsoft Edge浏览器Internal Server Error问题解决

网页无法在Microsoft Edge浏览器&#xff0c;尝试Google浏览器可以&#xff0c;排除服务器问题&#xff0c;应该是浏览器本身的问题。 一般这种都是和cookie有关&#xff0c;尝试删除记录 解决&#xff01;

【MQTT】Vue中使用mqtt

MQTT&#xff08;Message Queuing Telemetry Transport&#xff09;作为一种轻量级、开放、灵活、简单、易于实现的通信协议。它基于发布/订阅&#xff08;Publish/Subscribe&#xff09;模式的消息传输协议&#xff0c;在上位机和硬件设备间通信时经常用到。虽然在嵌入式软件一…

【图解物联网】第4章 先进的感测技术

4.1 逐步扩张的传感器世界 在前面的章节中&#xff0c;传感器的概念是“用来获取温度和湿度等纯数据的电子零件”。温度传感器和加速度传感器等确实是用来获取简单数据的小零件&#xff0c;我们可以将其理解为构成智能手机等电子设备的一个要素。 然而&#xff0c;随…

分布式文件存储与数据缓存(二)| Redis

目录 Redis概述_什么是NoSQLNoSQL的四大分类KV型NoSql&#xff08;代表----Redis&#xff09;列式NoSql&#xff08;代表----HBase&#xff09;文档型NoSql&#xff08;代表----MongoDB&#xff09;搜索型NoSql&#xff08;代表----ElasticSearch&#xff09; 关系型数据库和非…

Aspose.PDF功能演示:在 JavaScript 中优化 PDF 文件

PDF 文件是一种普遍存在的文档共享格式&#xff0c;但它们有时可能会很大&#xff0c;导致加载时间变慢并增加存储要求。优化 PDF 文件对于确保无缝的用户体验至关重要&#xff0c;尤其是在 Web 应用程序中。因此&#xff0c;在这篇博文中&#xff0c;我们将探讨如何使用 JavaS…

NCV4266ST50T3G线性稳压器芯片中文资料规格书PDF数据手册引脚图参数图片价格

产品概述&#xff1a; NCV4266 是一款集成了 150 mA 输出电流的低漏稳压器系列&#xff0c;可用于严酷汽车环境。它包括了较宽的运行温度范围和输出电压范围。该器件提供 3.3 V、5.0 V 固定电压版本&#xff0c;以及可调电压版本&#xff0c;输出电压准确度为 2%。它具有较高的…

IDEA 下载依赖包源码报错 Cannot download sources Sources not found for:XXX

最近在做一个功能的时候想看一个库的源码&#xff0c;结果源码下不下来&#xff0c;报Cannot download sources Sources not found for:XXX,网上搜了半天&#xff0c;也找不到靠谱的结论 后来想了下&#xff0c;应该是镜像那边出了问题&#xff0c;把镜像一删&#xff0c;源码…

HTML静态网页成品作业(HTML+CSS)——非遗徽州木雕网页(6个页面)

&#x1f389;不定期分享源码&#xff0c;关注不丢失哦 文章目录 一、作品介绍二、作品演示三、代码目录四、网站代码HTML部分代码 五、源码获取 一、作品介绍 &#x1f3f7;️本套采用HTMLCSS&#xff0c;未使用Javacsript代码&#xff0c;共有6个页面。 二、作品演示 三、代…

Linux nginx 域名申请证书后无法使用(无法访问此网站)阿里云域名

首先我们一步排除 1、域名备案是否成功&#xff1f; 网站备案_ICP备案_备案迁移_备案-阿里云 2、域名是否解析&#xff08;我就是错在这里&#xff09; 阿里云登录 - 欢迎登录阿里云&#xff0c;安全稳定的云计算服务平台 3、是否申请证书成功&#xff1f; 4、nginx是否支持…

【云原生 • Kubernetes】认识 k8s、k8s 架构、核心实战

文章目录 Kubernetes基础概念1. 是什么2. 架构2.1 工作方式2.2 组件架构 3. k8s组件创建集群步骤一 基础环境步骤二 安装kubelet、kubeadm、kubectl步骤三 主节点使用kubeadm引导集群步骤四 副节点加入主节点步骤五 部署dashboard Kubernetes核心实战1. 资源创建方式2. Namespa…

Beamer模板——基于LaTeX制作学术PPT

Beamer模板——基于LaTeX制作学术PPT 介绍Beamer的基本使用安装和编译用于学术汇报的模板项目代码模板效果图 Beamer的高级特性动态效果分栏布局定理环境 介绍 在学术领域&#xff0c;演示文稿是展示和讨论研究成果的重要方式。传统的PowerPoint虽然方便&#xff0c;但在处理复…

python爬虫之爬虫入门

import requests rrequests.get("http://www.baidu.com") print(r.status_code)#用status_code来确定页面状态是否正常 type(r) r.headers requests库入门 status_code可以用来检验网页状态是否正常type(r)返回r的类型r.headers返回该页面头部信 运行结果如下&#x…

SQLiteC/C++接口详细介绍sqlite3_stmt类(二)

返回目录&#xff1a;SQLite—免费开源数据库系列文章目录 上一篇&#xff1a;SQLiteC/C接口详细介绍sqlite3_stmt类简介 下一篇&#xff1a;SQLiteC/C接口详细介绍sqlite3_stmt类&#xff08;三&#xff09; sqlite3_reset() 功能&#xff1a;重置一个准备好执行的SQL语…

跨越时空的纽带:探索Facebook如何连接人与人

引言 Facebook作为全球最大的社交媒体平台之一&#xff0c;已经成为了人们日常生活中不可或缺的一部分。它不仅仅是一个社交网络&#xff0c;更是连接人与人、人与世界的纽带。在这篇文章中&#xff0c;我们将深入探讨Facebook如何跨越时空&#xff0c;连接人与人之间的关系&a…

Idea 不能创建JDK1.8的spring boot项目

由于https://start.springboot.io/ 不支持JDK1.8&#xff0c;那么我们需要换idea的springboot创建源&#xff0c;需要换成 https://start.aliyun.com&#xff0c;这也是网上大部分教程说的&#xff0c;但是我这边会报这样的错误&#xff1a; Initialization failed for https:…