JSON Schema与表单验证

作者:神机算子,美团金融前端团队成员。喜欢简单,乐于编程,富有激情的前端开发者。

表单验证是一个前端常聊的问题,在这个问题上实际上已经有很多种方案了,大体来说有以下两种:

  • 自己定义验证原语,进行简单封装,按需定制。这个方案好在对于简单的小表单上手快,几经提炼可以形成自己的验证库,也可以代码保持的精简。但是出现跨项目复用的时候,容易出现需要补充大量新场景的情况,而且稳定性也不容易保证。
  • 使用市面上已有的表单验证库。这个方案能秒杀大部分场景,但可定制性往往比较差,有些验证库方案甚至是基于某种组件库的。另一方面,一旦开始使用某种验证库,未来想要切换就非常棘手。

那么这里说的方案是否能超越这两种方案呢?这要从JSON Schema本身是什么说起。

JSON Schema是一种用JSON数据来描述需要验证的JSON的格式。利用这种格式,可以做到:

  • 有据可依。每一种验证方式都有固定的写法,即使某一天跨语言,也只需很小的迁移成本。
  • 包罗万象。JSON Schema是一个在不断发展的标准,基本上你想要的验证方法都在里面囊括了。
  • 文本为准。JSON本身只是一段文本,因此这种验证方法无需特别的工具即可编写,也很利于保存和分享。

ajv是JS实现的JSON Schema库。目前来说,它的性能和标准实现覆盖都比较好,具体可以看它项目主页的自我宣传。

在不使用任何验证库、验证工具的情况下,要验证表单需要逐个字段进行读取、判断。表单字段越多,代码的复杂度就越高,而且如果多个表单存在一定的共性,如何复用表单验证也是一个麻烦事。
比如:

图1

单从可读性来说,这段代码非常易读,因为它足够直白、简单,但如果所有的表单验证都这样做,非常容易出错,也不便于维护。

ajv本身只是一个验证工具,这个工具接受一个JSON Schema和你的目标数据,然后返回验证结果。和其他很多验证工具类似,ajv提供了默认的报错文案,默认情况下是英文的。

不过这个无法满足产品对表单验证的需求。理想的表单验证实际上包含以下需求:

  • 对于每个异常的字段,都需要指出其错误
  • 错误需要是产品自己所希望的文案,而不是某种库的内置文案,更别说是英文或者代码中的字段名了
  • 表单验证需要是有序的。直觉上来说,表单验证需要先报页面上最顶端的字段的问题。

对于第一点,ajv完善提供了错误信息。但对于第二点,ajv没有提供比较好的方式来处理,因为它的报错信息是非常程式化的,对于某一类错误,它的文案都是套路。
针对这一点,引入ajv-errors就比较合理了。ajv-errors需要开发在原有的schema中增加一个自定义字段,这个字段对每一种报错都可以定制自己的报错文案,大致如下:

图2

图中errorMessage字段是ajv-errors需要的字段。
这样一来,报错文案的可定制性就非常强了。
那顺序如何保证呢?
一般来说,JSON Schema中如果要验证一个Object的属性,是没有显式顺序的,这个就好像Object在遍历时本身就没有顺序一样。在界面上每个字段的位置,对于JSON Schema来说是透明的,无关的。

幸好ajv的报错是数组形式返回的。尽管数组的顺序在文档中没有明确指出,但这个报错的格式非常友好,它会表明自己是哪个字段。根据这一点,开发只需对报错数组进行一次排序即可,大致如下:

图3

图的顶端指定了字段的顺序,而尾端则使用这个顺序进行了排序。

完美,产品所有的需求都搞定了。

但作为一个合格的前端工程师,我自己是不能就这样收工的。实际上在引入了ajv和ajv-errors之后,前端的JS资源在minify之后膨胀了100KB左右,即使因为gzip能够做到只增加数十KB,这个结果也是不太理想的——太大了。

针对这个情况,如果退一步作为任意项目来对待,那可能我比较想要的做法是将这两个库都进行异步按需加载。这样做的话,多出来的尺寸基本上不会对首次加载造成影响,而且也足够灵活。

但是我们这个项目受限于现有发布系统,没有办法支持webpack的异步按需加载。这怎么搞?

我自己的想法是,将验证挪到node当中去做,让服务器完成这个过程,并将结果返回。

方案是:node端当中内置若干schema,并对每个schema命名,新加一个接口;浏览器端将需要验证的数据和schema的名字发送到node端,并取回验证结果。

从某种角度来说,这也是一种按需加载。粗略来看,这个验证在浏览器端可能会被恶意用户跳过,但只要你提交数据的接口最终没有完善的验证,那其他任何地方所增加的验证都是可以被绕过的,放在浏览器还是node,也就没什么区别了。

从长远来看,这个验证的过程也可以再追加到业务接口上,这样就无法被绕过了。

最后回过头来看,基于JSON Schema的表单验证方案不仅能够解决我们在表单验证上的基本需求,同时也在稳定性、可扩展性等方面有一定优势,适合于绝大部分表单验证的场景。

最后,团队为了招聘方便,整了个公众号,主要是一些招聘信息,团队信息,所有的技术文章在公众号里也可以看到,对了,如果你想去美团其他团队,我们也可以帮你内推哦 ~

二维码
### 如何使用 JSON Schema 创建动态表单并在 H5 页面中实现 #### 定义 JSON Schema 结构 为了创建动态表单,首先需要定义一个描述所需输入字段及其验证规则的 JSON SchemaJSON Schema 是一种用于描述和验证 JSON 数据结构的标准格式。 ```json { "$schema": "http://json-schema.org/draft-07/schema#", "title": "User Information", "type": "object", "properties": { "name": { "type": "string", "title": "Name" }, "age": { "type": "integer", "minimum": 0, "maximum": 120, "title": "Age" } }, "required": ["name", "age"] } ``` 此示例展示了如何定义用户名字和年龄两个属性,并设置了必填项[^1]。 #### 集成 Vue JSON Schema Form 库 接下来,在项目中集成 `vue-json-schema-form` 库来渲染上述定义好的 JSON Schema 成为实际可交互的 HTML 表单组件。由于该库支持多个版本的 Vue 及不同 UI 组件库,因此可以根据具体需求选择合适的组合方式[^2]。 安装依赖: 对于 Vue CLI 用户来说,可以通过 npm 或 yarn 来安装所需的包文件: ```bash npm install vue-json-schema-form --save // or yarn add vue-json-schema-form ``` 引入并注册插件: 如果是在全局范围内使用,则可以在 main.js 中完成初始化操作;如果是局部应用的话,则可以直接在对应的 .vue 文件里按需加载即可。 ```javascript import VJSF from 'vue-json-schema-form'; app.use(VJSF); ``` 或者在单独组件内部: ```html <template> <div id="form-container"> <JsonSchemaForm :schema="mySchema"/> </div> </template> <script setup lang="ts"> import { ref } from 'vue' const mySchema = ref({ /* ... */ }) </script> ``` 这样就可以轻松地把之前编写的 JSON Schema 转换成可视化的 Web 表单了[^3]。 #### 后端 API 支持 为了让前端提交的数据能够被正确处理,还需要构建相应的 RESTful API 接口服务端逻辑部分可以采用 Node.js 下流行的 Express 框架快速搭建起一套完整的 CRUD (Create, Read, Update and Delete) 功能集[^4]。 综上所述,通过以上几个步骤便能成功实现在 H5 页面中利用 JSON Schema 构建自适应性强且易于维护管理的动态表单功能。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值