开源表单设计器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,一经查实,立即删除!

相关文章

ORACLE:VARCHAR2(4000)太小怎么办?

目录 数据备份&#xff1a; 1. 创建新列&#xff1a; 2. 迁移数据&#xff1a; 3. 验证数据完整性&#xff1a; 4.删除旧列&#xff1a; 5. 重命名新列&#xff08;如果需要保持原列名&#xff09;&#xff1a; 在Oracle数据库中&#xff0c;你不能直接通过ALTER TABLE语…

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

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

如何在ubuntu 18.04中升级python 3.6到3.7

在ubuntu下安装python 3.7有两种方法: 1,通过使用Deadsnakes PPA中的标准apt工具(本文暂时只介绍这种方法) 2,从源代码进行构建。 前提条件&#xff1a; 需要以root用户或具有sudo访问权限的用户身份登录才能在Ubuntu系统上安装软件包。 方法一&#xff1a;使用apt工具安装…

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包进行…

Spring Boot 配置中心与应用属性完美匹配 | 深入探究@ConfigurationProperties与@NacosPropertySource

ConfigurationProperties ConfigurationProperties 注解是 Spring Boot 中用于将外部配置文件&#xff08;如 YAML 或 properties 文件&#xff09;中的属性映射到 Java Bean 类属性的强大工具。 以下是关于 ConfigurationProperties 注解与 YAML 配置文件属性匹配规则的详细…

单片机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;而当你在本地环境中执行的…

Electron 开发环境搭建指南:从 Node.js 到第一个桌面应用

Electron 开发环境搭建指南&#xff1a;从 Node.js 到第一个桌面应用 第一步&#xff1a;安装Node.js第二步&#xff1a;初始化Electron项目第三步&#xff1a;创建用户界面第四步&#xff1a;运行Electron应用 相信看到这里的小伙伴已经是看到了第一篇对于 Electron 框架的介绍…

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;

接口、抽象类和内部类

共同点 都不能被实例化都可以包含抽象方法都可以有默认实现的方法 区别 接口主要是对类的行为进行约束&#xff0c;实现了某个接口就具有了对应的行为&#xff1b;抽象类主要用于代码复用&#xff0c;强调的是所属关系一个类只能继承一个类&#xff0c;但可以实现多个接口接…

arm核的DMPIS是如何计算的

直接看这篇&#xff1a;https://zhuanlan.zhihu.com/p/660155292 写的很好&#xff1a; "SA8155P的CPU算力计算如下&#xff08;按照A75性能提升50%来计算&#xff0c;即 5.2 * 1.5 7.8 DMIPS/MHz &#xff09; SA8155P算力 2.419GHz * 1核 * 7.8 DMIPS/MHz 2.131GH…

【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个页面。 二、作品演示 三、代…

Form当中method的post和get的区别?

1.get是从服务器上获取数据&#xff0c;post是向服务器传送数据。 2. get是把参数数据队列加到提交表单的ACTION属性所指的URL中&#xff0c;值和表单内各个字段一一对应&#xff0c;在URL中可以看到。。post 是通过HTTP post机制&#xff0c;将表单内各个字段与其内容放置在HT…