真实的前端开发到底是怎样的?是在浩如烟海的 npm 中追寻永远找不到的银弹?还是在日新月异的 ECMAScript 规范下探索梦想中的乌托邦?
前端发展十余年,沧海桑田,朝代更迭,从 vanilla.js,到 jQuery.js,到 Angular.js,再到如日中天的 React/Vue。中间不乏又有诸如 svelte 之类后起之秀。
隐藏在看似繁荣昌盛的表象之下的真相是什么?
前端技术发展迅猛,很多曾经的真理不停地被颠覆。
行为结构表现分层,是一个古老且实用的代码分层规范,但在 jsx 和 vue template 面前被碾压得粉碎。虽然有足够的理由可以解释这个现象,但仍然让那些遵循这个规范千百个日夜的人有些难以适从。
不止前端这一个小领域,整个世界每一天都在变化,我们也一直在努力适应。可是光努力还不够,如果适应速度追赶不上变化速度,就会落后,就要被淘汰。如果想一直成为一个优秀的工程师,就得有点儿自己的东西,能够支撑你在各个朝代之中生存。
认知既然经常被颠覆,那我们就得用别样的视角去观察,什么是真实。
最近两三年,我一直在使用 MVVM 框架。使用它们的原因很简单,流行的东西必定有其优势。它们能够很好的实现组件化和 UI 响应式。但最近我开始思考一个问题:“为什么一定要使用 MVVM 框架?”
一个阳光明媚的下午,我伸伸懒腰,泡了杯红茶,准备在群里和那群水友交流交流。正聊得起劲,突然收到朋友小张的私聊。他问我一个问题,Vuex 怎么样在浏览器刷新后保持数据?这是一个非常简单的问题。vue 我用的少,但还是知道这个问题的解决方案。于是我告诉他两种办法,一是用 localstorage,二是用 vuex-persistedstate。
小张开始研究第一种方案,实现功能后,又觉得自己代码封装性做的不够好,他想了想,还是选择使用现成的包。于是小张又顺理成章地在安装 vuex-persistedstate 时报了错。经过小张再三折腾,切换 npm 源,删除 node_modules,使用 yarn,删除 package.lock 等操作后,终于把这个包安装到他的项目中。
这个问题算是解决了,但是第二天小张又问了我几个问题。比如异步的 commit,store 怎样分块比较好等等。由于我当天工作比较忙,远程也不方便,于是小张提出周末请我吃饭,顺便帮他看看那几个问题。
周末在小张订的餐厅里帮他看代码,原来他的项目中只有一个用户信息需要全局存储。但是他公司只有他一个前端,自身水平有限,也没人指点他。就去网上搜,搞不定,又去找公司多年不写代码的技术经理寻求解决方案,最后被告知可以试试 Vuex。
我告诉小张,这需求根本就不需要用 Vuex,存到 localStorage 中,加密一下即可。
然后我又整体看了下他这个项目,一共六七个页面,而且除了两个表单以外,几乎都是展示性的页面。于是我告诉他,这个项目甚至可以不用 Vue。
“不,我必须用 Vue。”小张斩钉截铁的回答我。
“为什么?”
“Vue 是最好的框架,而且很多人也一直都在用。”
我一阵无语,同时也让我感到一种莫名的悲哀。
虽然最后我解决掉了他那几个问题,但我不认为他能够应对框架接下来要带给他的问题。
这世上每时每刻都有人死去。以前从不觉得死亡离我很近。直到冠状病毒地出现,我被迫戴上了口罩,去医院做了核酸检查,在小区物业办理了出入证,每天出入小区和公司都需要在门口检查体温,外卖只能送到小区门口...
这一系列地变化让我觉得死亡其实离我并不远,也许我的生命随时都可能被死神夺走。我挺怕死,但现在这种局势,没让我感到害怕,反而激起我对生命地热爱。
有些朋友诉苦说,公司的工资开始少发,甚至拖延。我们公司并没有这么做,工资一分不少,但项目也毫不延期。甚至于一周之内要上线三个项目。
大量的工作让我们不得不在在疫情期间招聘,于是我和两个同事戴着口罩在电脑前和电脑另一边同样带着口罩的面试者聊了半天。
公司的三个项目中,有一个项目问题最多。项目框架的 UI 部分主要是 vue 和 element-ui。疏于写 Vue 的我面对这个项目,可谓是一步一坑。
问题着实不少,就随便说两个吧。
第一个是布局样式方面的问题。
项目中有一个弹窗页面,基本布局如下:
页面实际上是 4 个组件,上方区域是 search 组件,下方区域是 list 组件。外层是一个 layout 组件,包裹两个组件。最外层是 element-ui 的 el-tabs 组件。
本来是一个很正常的页面,但是写这个页面的人没有考虑到 search 组件内元素过多的情况,如果搜索条件的输入框或者按钮过多,就会被截掉。因为他把 search 设置了 overflow: hidden;
。
现在要么把 search 改成带滚动条,或者让它自动换行。考虑到用户体验,我选择后者。
我想把 layout 组件改为 flex 布局,却不敢改。因为 search 区域的 display
是 float
。 list
区域是使用 margin-top
来固定位置的。这种布局实现很糟糕,但我一时半会没办法改变它。
我忽略了 css 的力量。项目的 scss 代码过于复杂,样式嵌套过深,加上又有 Vue 的 style 多个三目表达式和 !important
。牵一发而动全身,我不敢轻易冒险,只好另辟蹊径,用 js 的办法来解决这个问题。
思路比较简单,元素加载完毕,获取 search 区域的高度(sh)。拿 sh 减掉 search 区域原本一行的高度(soh),得到多出来的高度(ih)。再把 list 区域的 margin-top 加上 ih。
在 Vue 中,获取某个元素使用 ref。于是我用 ref 拿到 search 组件和 list 组件。之后再用 offsetHeight 和 offsetTop 来获取相应的高度。
伪代码如下:
这段代码运行的位置应该是放到组件的 mounted 生命周期中。可奇怪的是,layout 的 mounted 生命周期每次都会运行多次,而最终结果 listRef 和 searchRef 的 offsetHeight 与 offsetTop 的值都是 0。
造成这个问题的原因,我足足花了 30 分钟才调试出来。原来 el-tabs 的默认机制会把所有 el-tab 中的组件渲染出来。这就导致页面虽然只显示一个 tab 的内容,实际上有 N 个 tab。而其他 tab 中很多也用到了 layout 组件,也就是说一个页面存在了多个 search 组件和 list 组件,那些组件虽然没有显示到界面,但确确实实存在,所以它们的 offsetHeight 与 offsetTop 都是 0。
我在每个 tab 块的组件上加了 v-if,又在切换 tab 的回调函数中添加了与 v-if 对应的状态改变,才解了这个问题。
另一个问题也与 element-ui 相关,是一个比较隐秘的 Bug,如果 el-select 组件是通过循环产生的,那么选择 el-option 后,js 中的数据会发生变化,而 UI 并不会变化。
造成这个问题的原因是 Vue 的数据双向绑定出现了问题。
解决的办法是在渲染组件之前保证 data 中已经具有与 el-select 的 v-model 对应的这个属性,或者使用$set。因为 Vue 无法监听到新添加的属性。
项目上的问题算是解决了,同时又衍生出来一个新的问题。
我为什么花了这么久才解决这么一个小问题?
造成这个问题的原因可能是我对 Vue 的理解没有那么透彻,也可能是对 element-ui 的使用没有那么熟练。但这些都不是根本原因。
如果我认为这就是问题的根源,那我可能会去认认真真多读几遍 Vue 和 element-ui 的文档,可是这并不能改变生么。我清楚地意识到,这些都不是问题的根源。
上面说为朋友小张感到悲哀,为什么会悲哀呢?
小张工作两年多,最早是做 Java 开发的,做了一年多,今年刚转前端。我和他交集不多,但还是觉得他不是一个笨人。
在做 Java 开发时,小张最熟悉的前端框架是 jQuery 和 Bootstarp。作为老一代前端技术,相对比目前的主流技术,学习成本确实很低,开发也相对便捷,开发过程中可能遇到的问题也更少。
Vue 并不适合小张在目前阶段开发项目,他应该优先使用那些他能够驾驭得了的技术来为公司工作,而且就他的项目而言,MVVM 确实没有必要。坚持使用主流而不适合的技术,没有什么实际意义反而造成一堆不必要的麻烦。这是悲哀的第一点。
悲哀的第二点,是小张没有意识到这一点,并且在我告知他之后,仍没有意识到。
一旦当某个“最佳实践”成为主流,就会被疯狂的使用,但很少有人能够想起到它的初衷,它为何而存在。
理解不了的东西,要去悟。悟不明白,就醒不过来。
目前来说,前端的技术选型太过于复杂,在很多地方没有最佳方案。每个框架和库都有一套自己的说辞,确实它们都有自认为不错的优点。
react 和 vue,很多人都说它们很像,但实际上区别仍然不小。这也不单单是指它们自身,而是它们背后的整个生态链。常用的一些库,vue template 和 jsx、react-router-dom 和 vue-router、redux、mobx 和 vuex、redux 和 vuex 的中间件,ant design、material-ui 和 iview、element-ui、各自的 hooks 等等。样式层面同样也存在大量的选择,css in js、sass、less、styled-components...
可谓是百家争鸣,各有千秋。
这些技术你用的越深,掌握的越精通,就越能发现它们的区别。
从设计思想,到底层实现,再到风格迥异的 API,到处都是大同小异的细枝末节。
这些都是学习成本。也难怪去年 github 上发生了“学不动了”事件。
前端技术更新迭代的速度,已经达到了难以想象的程度。
你有没有那么一刻,停下来认真思考过,这些东西真的适合我们吗?
决定这个问题答案的因素有很多。
团队成员、历史项目、业务类型等等。有时候根本就不是一个人能够决定得了的。
但是,每时每刻都有公司在招聘,都有程序员在求职。你在上一家公司留下的项目,下一个来顶替你的人就得接着。而你认为即将可以大展身手的新公司,也不过是在接上一个离开的人给你留下的盘。
我也曾想,既然前端框架都是为了实现同一个目标,用户体验。那么技术为什么不能够统一呢?不能统一,究其原因是统一代表着思想禁锢。
实现同样一件事,有很多种方式。像 Vue 认为数据劫持和 Proxy 的 push 方式更好,而 React 则认为 diff 算法的 pull 方式更胜一筹。选择方式的不同,造成了思想的分歧。
世界为什么不统一?宗教为什么不统一?这又上升到了哲学的高度。
其实原因很简单,世界各国、各大宗教都有自己的信仰、思想、传统、价值观、利益、资源、文化知识。正是这样,才有了如今多元化的世界。
但换一个角度来看,人类是统一的。
在前端,每天都有大量的包如同新生儿一样出现在 npm 上。它们经过时间的沉淀、岁月的磨砺,有的成了“最佳实践”,有的则默默无闻。和人一样,有上层人士,有中产阶层,也有底层人群。它们有统一的地方。那就是浏览器、HTML、CSS 和 JavaScript。
前端领域有很多“维新主义”人士,他们不停的创造新的东西,来取代旧的东西。
流行的东西就是大势,而一直不变的东西就是真实。
大势所趋和返璞归真之间,选谁都不会错。
“势”一直都在,顺势而为,方为智者。但眼界得开阔,不要随便被一个不明白的概念唬住了。要明白,“势”是谁的“势”,“趋”还是“被趋”。
关键在于选择。
一个擅长使用 React 的开发者,让他来解决 jQuery 或者 Vue 上的问题,也许可以解决,但在解决问题的过程中会遇到很多困难,在效率上就无法达到 React 的那种程度。我称这种现象为问题之上的问题。
项目技术选型,要尽量符和主要开发者的技术池。如果选型有问题,那么问题自然不请自来,这时应该怎么办?来得及重新选择,就去重选。来不及,唯有迎难而上。
再朝上看一层,为什么要找一个川菜厨师来炒闽菜呢?
框架的选择没有绝对的好与不好,就像这个世界没有绝对的对与错一样。
MVVM 框架固然是好的,但也是复杂的。
做项目和买电脑一个道理,买新不买旧。但也区分用途。一个每天和文档打交道的办公室文员买一个 2 万的 MacBookPro 可能不如一个 4 千的 ThinkPad 好用。开发一个日常活动页面,就没必要用 MVVM 框架。开发一个小项目,也没必要用 Typescript。
我们需要评估一个项目是不是需要一种框架,这又涉及到如何区分大项目和小项目的边界。
通常情况下,这个边界总是模糊的。你如果一定要划清一道边界,来确定是否使用 MVVM 框架、TypeScript 或者其它技术,或许可以列出如下清单:
页面数超过 20 个。
模块数超过 5 个。
代码行数超过 5000 行。
项目人员超过 10 个。
...
即使你可以列出这么一个清单,仍然很难决断项目是否该用什么不该用什么。因为项目的整体难度只依靠可衡量的指标是不够的。比如一个项目只有几个页面,但都是些复杂的可视化页面,具有非常多的数据和彼此间错综复杂的数据联动,那这个项目就不算是小项目。或者一个项目有几十个页面,但页面整体都很单一,大都是些展示性页面,甚至一个页面就是一张图片加一些文字而已。那么这个项目就不能算是大项目。
当你感觉到项目的开发让你头痛时,你自然而然就会使用更加高级和复杂的框架来解决目前的问题。而不是在一切顺利进行的情况下强行使用高级而复杂的框架来给自己制造问题。
软件工程的思维和学习的思维是相反的。学习是要一直踏出舒适区,软件工程是要保持在相对稳定的状态。
除了项目因素以外,团队是第二个因素。
国内大多数公司的前端团队配置都少得可怜。80%的公司拥有专职前端,70%的公司前端人数都在 3 人以下。一个 100 多人的中大型技术团队,前端人数可能还不到 20 人。国内拥有 100 多人技术团队的公司看上去可能不少,但是在每个城市中却少得可怜。
这种形势下,强行使用 MVVM 框架、TypeScript、Graphql 之类的技术,有害无益。
但如果你没有绝对的实力和自信碾压面试官,就不得不跟风去学,因为各个公司在招聘时都会要求你掌握或精通某几项根本不适合他们公司的技术。
当生存的饭碗遭到威胁时,人就不再需要理智去思考为什么这么做。
MVVM 是优秀的思想和一套完整的解决方案,值得去学习,但不一定适合每个项目或每个人。
2 月中旬是最重视疫情的时候,那时整条大街一片空荡荡,去医院的人更少了。
集团下有个医院性质的公司。疫情期间为了开展业务,要在微信公众号上面放一组页面,用来暂时取代线下签约,改为在线签约的方式。
作为 C 端产品,没有使用 UI 组件库,页面样式和功能几乎全部手写。
项目不算复杂,一共四五个页面。几乎全部都是表单,具有各种联动。
这就涉及到了数据校验。
数据校验是为了保证数据的完整性、合法性而进行的一种处理手段。
数据校验这件事,有非常久远的历史。
在很久很久以前。还没有前端工程师,甚至都不存在服务端工程师时,很多应用程序的架构是一体化的。
那种程序的架构设计只有一层,或者说没有分层,业务逻辑可能放到数据库的存储过程中,用户界面和服务程序是一体的。那时的数据校验,是放在数据库上做的,只要数据符合创建表时设置的数据类型和长度,就能存储成功,否则就存储失败。与其说是在数据库上做校验,倒不如说没有校验,全靠硬怼。因为那时还没有数据校验这个概念。
浏览器流行后,web 应用出现在大众视野。开发者逐渐有了数据校验这个概念,但当时前端发展还处于蛮荒时代。没有 SPA,没有 AJAX,甚至还没有前端工程师这一说。页面都是由服务端模板渲染出来的,甚至在模板中写了大量的后端逻辑。由于技术原因,每次提交页面都会返回一个新的页面,所以数据都被刷掉了。当然也有缓存数据的办法,但那时候没有人在意这件事情,也不流行这种做法。时至今日,仍有些古老的网站停留在这个阶段。
再后来,出现了 AJAX,前后端分家,CS 架构、BS 架构,MVC、MVVM。随着人们对软件的探索,人们对用户体验度越来越重视。软件架构越来越规范,应用质量越来越高,数据校验也就成了一个必不可少的部分。
现在仍有一个争议,前端到底需不需要做数据校验?
答案是需要,数据校验是一个前端非常有必要去做的事情,有很多理由可以证明它确实需要做。但也存在一些特殊的情况。
如果后端做了数据校验,并且把校验失败信息精确的在接口中返回,那么就可以在一定程度上允许前端不做数据校验。
这种情况下前端做数据校验,唯一的好处就是能够减少一次接口的调用,能够减少服务器的压力。
一些工期短、用户少的小项目。如果受到各种因素影响,就可以不做。但能做尽量还是要做。
无论前端如何后端接口都一定要做数据校验。
目前来说,前端的数据校验有两种。
第一种是实时校验,每次输入完毕就会进行一次校验,并把这个校验结果反馈给用户。
第二种是提交时校验,当一个表单被提交时进行统一校验。
两种方式各有各的好处,但是从用户体验角度讲,大部分场景下都是提交时校验更合适。因为频繁的实时校验会让用户产生厌烦感。
实时校验的实现比较简单,通过监听 input
、 change
等事件来完成。
提交时校验是通过在 form 的 submit
事件中校验数据,根据校验结果做不同的处理。
B 端项目,大部分的数据校验都是放在 UI 组件库中做的,因为非常方便。
在使用组件库的情况下,几乎都有一个叫做 Form
的组件。 Form
组件几乎都带有数据校验的功能,而且用法也都大同小异。
拿 Ant design 举例。
只需在 Form.Item
的 rules
属性中配置相关校验逻辑,即可实现输入的校验。
<Form> <Form.Item {...formItemLayout} name="username" label="Name" rules={[ { required: true, message: "Please input your name", }, ]} > <Input placeholder="Please input your name" /> </Form.Item> </Form> 复制代码
之后可以在提交表单的函数中使用 form.validateFields()
来校验。
用起来不怎么复杂,实际上背后做了不少事情。
html 本身也存在数据校验功能。
input 的 type
属性就可以做到最基本的校验功能,比如校验 email
、 url
等格式。
除了 type
属性外,还有 required
、 min
、 max
、 pattern
等属性可以对数据进行校验。
JavaScript 也提供了 validity
接口,可以自定义校验的状态以及错误提示。
使用 el.setCustomValidity('校验失败')
来设置错误消息。使用 el.setCustomValidity('')
来取消错误消息。
下面是目前所有校验相关属性。
浏览器的表单错误提示中,都是提交时校验。但由于不同的浏览器实现不同,具体的效果也不一致。大体又分两种。
第一种是只对校验失败的第一个结果做出提示。
比如 Chrome 80。
第二种是对所有校验失败做出提示。
比如 Edge44 和 IE11。
除了显示效果不同外,默认的提示文字也不同。
validity
特性出来好些年了,目前来说使用率仍很低。究其原因无非是兼容性差、浏览器的不一致性、样式难以定制等。如果你感兴趣,可以参阅 更多资料 。
后端和前端的数据校验并没有什么太大差异,区别在使用位置和写法。
使用位置上,前端主要是在数据提交到后端前做校验,校验失败停止提交并对用户作出提示。后端主要是数据进入逻辑处理前,在控制器中做校验,校验失败抛出异常并在接口返回错误提示。
写法上,不同的语言和不同的框架,都不同。
我用过最优雅的写法大概是 Java 的 Java Bean Validation
。
大致代码是这样的。
@Getter @Setter @ToString public class User { @NotNull(message = "用户名不能为空") public String username; @NotNull @NotEmpty private List<@Email String> emails; @Future private Date endDate; } 复制代码
Bean Validation
是 Java EE JSR 规范,具体实现是 Hibernate Validator
。
在 Hibernate Validator
中只需要一个注解即可实现数据校验, Hibernate Validator
内置了大量注解。
Java Bean Validation 内置的 constraint。
@Valid | 作用 |
---|---|
@Null | 被注释的元素必须为 null |
@NotNull | 被注释的元素必须不为 null |
@AssertTrue | 被注释的元素必须为 true |
@AssertFalse | 被注释的元素必须为 false |
@Min(value) | 被注释的元素必须是一个数字,其值必须大于等于指定的最小值 |
@Max(value) | 被注释的元素必须是一个数字,其值必须小于等于指定的最大值 |
@DecimalMin(value) | 被注释的元素必须是一个数字,其值必须大于等于指定的最小值 |
@DecimalMax(value) | 被注释的元素必须是一个数字,其值必须小于等于指定的最大值 |
@Size(max, min) | 被注释的元素的大小必须在指定的范围内 |
@Digits (integer, fraction) | 被注释的元素必须是一个数字,其值必须在可接受的范围内 |
@Past | 被注释的元素必须是一个过去的日期 |
@Future | 被注释的元素必须是一个将来的日期 |
@Pattern(value) | 被注释的元素必须符合指定的正则表达式 |
Hibernate Validator 附加的 constraint。
注解 | 作用 |
---|---|
被注释的元素必须是电子邮箱地址 | |
@Length(min=, max=) | 被注释的字符串的大小必须在指定的范围内 |
@NotEmpty | 被注释的字符串的必须非空 |
@Range(min=, max=) | 被注释的元素必须在合适的范围内 |
@NotBlank | 被注释的字符串的必须非空 |
---|---|
@URL(protocol=, host=, port=, regexp=, flags=) | 被注释的字符串必须是一个有效的 url |
@CreditCardNumber | 被注释的字符串必须通过 Luhn 校验算法, 银行卡,信用卡等号码一般都用 Luhn 计算合法性 |
@ScriptAssert (lang=, script=, alias=) | 要有 Java Scripting API 即 JSR 223 ("Scripting for the JavaTM Platform")的实现 |
@SafeHtml (whitelistType=, additionalTags=) | classpath 中要有 jsoup 包 |
如果要扩展自己的校验规则,还可以使用自定义注解。
遗憾的是,目前 JavaScript 还不支持注解,但在 TypeScript 可以使用注解功能。
node.js 中最流行的数据校验库非 validator 莫属。npm 周下载量 330 万+。
validator 不仅限于 node.js,在 JavaScript 模块和脚本中都可以使用。内置的函数非常之多,涵盖日常开发中大部分场景。
语法还是 JavaScript 一贯的函数式语法。
var validator = require("validator"); validator.isEmail("foo@bar.com"); //=> true 复制代码
如果使用 TypeScript 开发 node.js 程序,是可以使用注解特性的,所以就有了类似于 Java Bean Validation
的优雅写法。
对比 validator,class-validator 在 npm 周下载量仅有 30 万,可见 Typescript 的流行程度仍有待提高。
语法如下:
import { validate, validateOrReject, Contains, IsInt, Length, IsEmail, IsFQDN, IsDate, Min, Max, } from "class-validator"; export class Post { @Length(10, 20) title: string; @Contains("hello") text: string; @IsInt() @Min(0) @Max(10) rating: number; @IsEmail() email: string; @IsFQDN() site: string; @IsDate() createDate: Date; } let post = new Post(); post.title = "Hello"; // should not pass post.text = "this is a great post about hell world"; // should not pass post.rating = 11; // should not pass post.email = "google.com"; // should not pass post.site = "googlecom"; // should not pass validate(post).then(errors => { // errors is an array of validation errors if (errors.length > 0) { console.log("validation failed. errors: ", errors); } else { console.log("validation succeed"); } }); validateOrReject(post).catch(errors => { console.log("Promise rejected (validation failed). Errors: ", errors); }); 复制代码
写了那么多,终于轮到本文的主角登场了。
lvp.js 是一个数据校验库。
最开始写这个库,并没有打算开源。因为有太多类似的库,而且我实在是找不到这个库有什么优秀的地方。
在一个老旧的项目里,填埋一个前任留下的坑。
用了一整个下午,重构了那个名为 validate 的类。
非常巧的是,当天下午下班前,有个朋友问我有没有比较通用的 JavaScript 数据校验库?
于是第二天我就把项目发布到 npm 上了。
然后又花了一个周末,把文档和测试都做好了。于是就有了 lvp.js 。
语法比较简单:
var Lvp = require("lvp.js"); // 把 lvp 导入进来 var lvp = new Lvp(); // 创建 Lvp 实例 var phone = "15555555555"; // 测试数据 var isPhone = lvp.test({ value: phone, rules: "isCNPhone" }); // 开始数据校验 //{message: "校验成功", status: true} 复制代码
如果你需要测试一堆数据,比如表单提交,那么代码是这样的。
var orderInfo = { orderId: "tb12395x5zv4003y", idCard: "37188019840918666X", phone: "18854100312", }; var tr = lvp.test([ { value: orderInfo.idCard, rules: "isCNIDCard", message: "身份证格式错误", }, { value: orderInfo.phone, rules: "isCNPhone", message: "手机号格式错误", }, ]); // {message: "校验成功", status: true} 复制代码
如果内置校验逻辑不够用了,可以添加自己的校验逻辑。比如添加斐波那契和二狗的校验。
lvp.addRules([ function isFibonacci(value) { function fibonacci() { if (value == 0) { return 0; } else if (value == 1) { return 1; } } return fibonacci(value - 1) + fibonacci(value - 2); }, function isTwoDog(value) { return value === ":dog::dog:"; }, ]); 复制代码
更多示例就不一一列举了,喜欢的话可以去官网看看。
与其它同类库相比,lvp.js 更是像一头小萝莉,小巧极简但又刚好能满足。
源代码用 ES5 写的,不用编译,去掉注释 200 行左右,min 版本体积 3k 多一点。没有过度设计的内容,上手非常简单,语法容错率非常高,支持 CommonJS、AMD、CMD、ESM 各种规范。可以在 node.js、React、Vue、jQuery、或者原生 HTML 中使用。
单元覆盖率 93.89%,剩下几行是兼容代码,在 jest 中不容易被测试到。
目前内置校验规则比较少,但都是日常开发中使用频率非常高的校验逻辑,特别是中国的程序员。
校验列表还在不断补充,如果你在工作中遇到使用频率非常高的数据校验逻辑,欢迎提交 PR 。