简介:这是一份面向Web前端开发者的jQuery Validate插件1.8.1版本配套实例包。插件通过HTML属性与JavaScript配置即可完成表单字段的必填、邮箱、URL、数字、长度等校验,并支持自定义验证规则与错误消息定制,适用于需要快速构建可靠表单验证的中级前端工程师,也可作为初学者了解前端数据校验机制的入门范例。压缩包共有165个文件,约603KB,包含70个JS脚本、21个HTML演示页面、15个CSS样式表,以及GIF/PNG图片素材和若干PHP服务端示例,目录结构清晰,便于按需查阅。该资源已有1864人学习下载。实例包中除了插件主文件,还提供了完整的集成示例,涵盖基础验证、自定义验证方法、消息提示以及提交拦截等关键用法,可帮助开发者对照代码快速上手,减少在表单校验上的重复开发工作,也可作为团队前端表单校验组件的基础参考。
1. 表单校验的重复劳动,jquery.validate.js 1.8.1 怎么把它收进配置里
接手一个多年没动过的老系统,前端还是 jQuery 那套,注册页和后台表单的校验逻辑散落在每个按钮的 click 事件里,改一处规则要翻好几天代码。jquery.validate.js 1.8.1 正是收拾这种局面的老牌插件:只要在validate()配置里声明字段规则和提示文案,插件就会在失焦、按键、点击提交时自动触发校验,把错误提示直接插到表单旁边,省掉一整套手写判断。对还在维护历史项目的人,以及想快速给登录、注册、配置表单补齐校验的开发者来说,这个方向至今依然够用、够稳。下面先从运行机制讲起,再给最小实例、参数配置和五个高频翻车点,最后落到 AJAX 提交的完整做法。
2. jquery.validate.js 1.8.1 的运行机制:从规则声明到错误提示生成
2.1 validate() 是入口:一次配置,插件接管表单
这个插件所有能力都集中在$(form).validate(options)这个方法上。调用之后,插件会给表单绑定提交事件,给表单内的可见输入控件绑定失焦和按键事件,后续的交互都由它接管,不需要再手动触发校验。配置项里的rules对应每个字段的要求,messages对应每条规则要展示的文案,两个对象的结构完全一致,都是以控件name作为 key。
$('#signupForm').validate({ rules: { username: { required: true, minlength: 3 } }, messages: { username: { required: '请输入用户名', minlength: '用户名至少 3 个字符' } } });逻辑说明:rules里的 key 必须写成表单控件的name属性,写成id不会生效。required: true表示必填,minlength: 3表示最小长度。messages里的 key 与规则名一一对应,写错规则名时文案会不显示。参数说明:validate()本身只负责初始化,返回值是校验器实例,后面做rules('add')、resetForm()都要靠这个实例。如果在 DOM 还没加载完时调用,选择器可能取不到表单,所以通常放在$(function() { ... })里。
2.2 触发时机与默认行为:blur、keyup、click 怎么配合
1.8.1 默认会在三个时机做校验:输入框失去焦点时检查当前字段,用户按键时再次检查,点击提交按钮或按回车时检查整个表单。checkbox、radio、select 这类控件则是在点击时触发。这个设计很实用,用户还没填完时不会提示,填完离开字段立刻反馈,改错了马上变绿。
默认的错误提示元素是label,会带上class="error",插入到对应输入控件后面;校验通过后会把错误 label 移除,同时给控件加上valid类。通过focusInvalid参数可以控制在提交失败后是否把焦点跳到第一个出错字段,默认是跳,省得用户自己找。invalidHandler可以用来拦截提交,比如统计错误数量后统一弹提示。
$('#signupForm').validate({ rules: { /* ... */ }, messages: { /* ... */ }, onkeyup: true, onfocusout: true, onclick: true, focusInvalid: true, invalidHandler: function(event, validator) { var errors = validator.numberOfInvalids(); if (errors > 0) { alert('还有 ' + errors + ' 个字段填写不正确'); } } });逻辑说明:onkeyup、onfocusout、onclick对应三类触发开关,默认都是打开,不需要全部配置,只在想关闭某种触发时才需要显式写。invalidHandler只在提交时有无效字段才执行,适合做统一的错误汇总。参数说明:validator.numberOfInvalids()是 1.8.1 提供的统计方法,返回无效字段数;event是原始事件对象,一般用不到。
2.3 同样用 jQuery,为什么老项目优先选它而不是手写
手写校验也不是不行,但问题很固定:每个输入框都要写 blur 监听、keyup 监听,提交循环里还要遍历所有字段,代码一多就漏。validate 插件把「规则声明」和「执行逻辑」拆开了,业务只需要维护rules和messages,触发、错误插入、焦点跳转这些通用能力全部复用。还有一个实际好处是对老浏览器兼容性高,1.8.1 在 IE 时代的页面上也能跑,正好匹配很多企业项目里的遗留系统。
选它的时候也要看清边界:它只负责浏览器端体验,服务端入参校验该做还得做,永远不要把客户端校验当作安全防线。和 FormValidation、Parsley 这些后来的库相比,1.8.1 的 API 更贴近 jQuery 生态,学习成本低,中文资料也多,适合当前端还是 jQuery 主导的项目。如果项目已经用 Vue 或 React 重写了,那就不该硬塞这个老插件,用框架自己的校验方案更合适。
3. 直接能用的注册表单实例:引入文件、写规则、调错误位置
3.1 引入顺序与版本匹配:先 jQuery 后插件
页面里必须先引入 jQuery,再引入 jquery.validate,顺序反了插件会直接报错。1.8.1 是十多年前的版本,早年说明里标注兼容 jQuery 1.3.2 以上,实际维护老项目时我习惯配 jQuery 1.7 到 1.9 区间的版本,整体比较稳。用最新的 jQuery 3.x 去配它会遇到兼容问题,后面避坑章会细说。
<meta charset="UTF-8"> <script src="js/jquery-1.9.1.min.js"></script> <script src="js/jquery.validate.min.js"></script> <script src="js/additional-methods.min.js" (可选)></script>逻辑说明:jquery.validate.min.js是核心文件,additional-methods.min.js是扩展规则包,用不到扩展规则时可以不引。所有引入都放页面底部也行,但要保证在业务脚本之前。参数说明:文件用本地相对路径,避免依赖外网资源,内网部署的老系统尤其要这样。
3.2 一个最小注册表单的完整代码
下面这个表单覆盖了必填、长度、邮箱格式、两次密码一致四类最常见的校验。HTML 结构保持简洁,业务代码如下。
<form id="signupForm" action="/register" method="POST"> <div class="form-item"> <label>用户名</label> <input type="text" name="username" id="username"> </div> <div class="form-item"> <label>邮箱</label> <input type="text" name="email" id="email"> </div> <div class="form-item"> <label>密码</label> <input type="password" name="password" id="password"> </div> <div class="form-item"> <label>确认密码</label> <input type="password" name="confirm_password" id="confirm_password"> </div> <button type="submit">注册</button> </form> <script> $(function() { $('#signupForm').validate({ rules: { username: { required: true, minlength: 3, maxlength: 12 }, email: { required: true, email: true }, password: { required: true, minlength: 6 }, confirm_password: { required: true, equalTo: '#password' } }, messages: { username: { required: '请输入用户名', minlength: '用户名至少 3 个字符', maxlength: '用户名最多 12 个字符' }, email: { required: '请输入邮箱', email: '邮箱格式不正确' }, password: { required: '请输入密码', minlength: '密码至少 6 位' }, confirm_password: { required: '请再次输入密码', equalTo: '两次输入的密码不一致' } } }); }); </script>逻辑说明:equalTo: '#password'的取值是选择器,插件会把当前字段的值和这个选择器对应控件的值做比对,密码确认是它的典型场景。rules里每一项都对应一个校验规则,多个规则用逗号分隔。参数说明:maxlength: 12除了限制字符数,在部分浏览器里还同时影响输入框可输入的最大长度;email: true走的是正则校验,不是 HTML5 的type="email",会严格检查@和域名结构。这里没有给submitHandler,校验通过后会走原生表单提交,页面会跳转到action地址。
3.3 错误提示的位置与样式:errorPlacement 和 errorClass 怎么调
默认的错误提示插到输入框后面,但真实项目里往往要精确控制位置,比如统一放到.form-item的最下方。errorPlacement就是干这个的,它接收两个参数:生成的错误元素和当前校验的控件元素。errorClass控制错误提示的类名,highlight和unhighlight控制在字段出错、通过时给外层容器加类,方便写样式。
$('#signupForm').validate({ rules: /* ... */, messages: /* ... */, errorPlacement: function(error, element) { if (element.is(':radio,:checkbox')) { element.closest('.form-item').append(error); } else { error.insertAfter(element); } }, errorClass: 'invalid', errorElement: 'span', highlight: function(element) { $(element).closest('.form-item').addClass('has-error'); }, unhighlight: function(element) { $(element).closest('.form-item').removeClass('has-error'); } });逻辑说明:errorPlacement里判断了 radio 和 checkbox,因为这类控件的错误提示插到单个输入框后面很难看,统一放进外层容器更合理。highlight在字段校验失败时触发,unhighlight在通过时触发,配合.has-error类就能让整个表单项边框变红。参数说明:errorElement可以指定生成span、label、div,默认是label;改成span可以避免和原有 label 嵌套冲突。给errorClass改名后,CSS 里对应的.invalid颜色、字号都要自己写,不会再命中默认的.error样式。
4. 内置规则和参数配置:记好这张表和四种扩展方式
4.1 1.8.1 内置规则速查表
大部分表单业务常用的校验规则插件都内置了,不需要额外引入。下面这张表按使用频率排列,规则名就是rules里的写法。
| 规则名 | 作用 | 配置示例 | 适用控件 |
|---|---|---|---|
| required | 必填 | { required: true } | 文本、密码、下拉、单多选 |
| 邮箱格式 | { email: true } | 文本 | |
| url | URL 格式 | { url: true } | 文本 |
| number | 数字,允许小数 | { number: true } | 文本 |
| digits | 纯整数 | { digits: true } | 文本 |
| minlength | 最小长度 | { minlength: 6 } | 文本 |
| maxlength | 最大长度 | { maxlength: 20 } | 文本 |
| rangelength | 长度区间 | { rangelength: [6, 20] } | 文本 |
| min | 数值下限 | { min: 1 } | 数字、文本 |
| max | 数值上限 | { max: 100 } | 数字、文本 |
| range | 数值区间 | { range: [1, 100] } | 数字、文本 |
| equalTo | 与另一字段相等 | { equalTo: '#password' } | 文本 |
| remote | 远程接口校验 | { remote: 'check.php' } | 文本 |
| date | 日期格式 | { date: true } | 文本 |
| dateISO | ISO 日期格式 | { dateISO: true } | 文本 |
| creditcard | 信用卡号格式 | { creditcard: true } | 文本 |
逻辑说明:min、max、range比较的是数值,用type="text"时插件也会自动转成数字比较,所以不用特意改输入框类型。rangelength对中文和英文都按字符数算,不是字节数,表单里限制长度时要注意这一点。参数说明:remote是异步校验,后面单独讲,表格里先知道它存在就行。
4.2 messages 的三种写法与全局默认提示
messages的配置方式有三种。第一种是在validate()里像前面那样逐条写,直观但字段多时冗余;第二种是复用全局默认提示,适合统一文案;第三种是直接在$.validator.messages上扩展,和语言包机制一样。
// 全部字段共用一套默认提示 $.extend($.validator.messages, { required: '该字段不能为空', email: '请输入有效的邮箱地址', url: '请输入合法的网址', minlength: $.validator.format('长度不能少于 {0} 个字符'), remote: '该内容已被占用' }); $('#signupForm').validate({ rules: { username: { required: true, minlength: 3 } } });逻辑说明:$.validator.format是插件提供的模板方法,{0}会替换成规则参数,比如minlength传 3,提示就变成“长度不能少于 3 个字符”。局部messages没写的规则会优先走全局默认提示,全局没定义的就显示英文。参数说明:$.extend是 jQuery 的合并方法,这里可以在页面加载时执行一次,让所有表单复用。这个方案比在每个validate()里重复写messages省事得多。
4.3 addMethod 扩展业务规则:手机号、身份证这类自定义校验
内置规则覆盖不了业务规则,比如手机号、身份证、统一社会信用代码。addMethod(name, method, message)可以注册一个全新规则,method函数的返回值决定是否通过。
$.validator.addMethod('phoneCN', function(value, element) { // this.optional(element) 在字段为空时直接返回 true,避免和 required 冲突 return this.optional(element) || /^1[3-9]\d{9}$/.test(value); }, '请输入正确的手机号'); $.validator.addMethod('idCard', function(value, element) { if (this.optional(element)) { return true; } if (!/^\d{17}[\dXx]$/.test(value)) { return false; } var factor = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2]; var parity = ['1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2']; var sum = 0; for (var i = 0; i < 17; i++) { sum += parseInt(value.charAt(i), 10) * factor[i]; } return parity[sum % 11] === value.charAt(17).toUpperCase(); }, '请输入正确的身份证号'); $('#memberForm').validate({ rules: { mobile: { required: true, phoneCN: true }, cert_no: { idCard: true } }, messages: { mobile: { phoneCN: '手机号格式不对,请重新填写' }, cert_no: { idCard: '身份证校验位不对' } } });逻辑说明:自定义规则里this.optional(element)是个关键约定,字段值为空时返回 true,这样必填性交给required管,格式规则只负责格式,两者互不干扰。addMethod的注册要在validate()调用之前执行,否则初始化时找不到规则。参数说明:phoneCN正则目前覆盖 13 到 19 开头的 11 位手机号,不同业务可以按号段调整;身份证示例用的是加权校验码算法,可以照搬到其他合规校验场景。
4.4 动态增删规则:rules('add') 和 rules('remove')
表单里经常有「选了某个选项后,另外几个字段变成必填」的需求。1.8.1 提供了rules('add')和rules('remove'),可以随时给已有控件增删校验规则,不用重新初始化整个表单。
var validator = $('#orderForm').validate({ rules: { delivery_type: { required: true } } }); $('#delivery_type').change(function() { if ($(this).val() === 'express') { $('#express_no').rules('add', { required: true, minlength: 6 }); } else { $('#express_no').rules('remove', 'required minlength'); } });逻辑说明:rules('add')会往控件现有的规则集合里追加,rules('remove')传入空格分隔的规则名字符串,被移除的规则不再参与校验。这样联动校验不需要写复杂的自定义方法,适合业务规则经常调整的后台表单。参数说明:如果调用rules('add')时控件原本没有校验规则,插件会自动把它纳入当前表单的校验范围;重复添加相同规则不会报错,但会有多次校验开销,建议先remove再add。
5. jquery.validate.js 1.8.1 避坑清单:五个高频翻车点与排查思路
5.1 页面脚本报错:插件在 jQuery 3.x 上直接失效
现象:在老项目基础上把 jQuery 升级到新版,刷新页面后打开控制台报xxx is not a function,点击提交按钮没有任何反应,表单直接被浏览器的原生提交处理了。
原因:1.8.1 内部依赖了旧版本 jQuery 的一些 API,新版本把这些 API 移除或改了行为,插件初始化阶段就抛出异常,后续校验逻辑完全没有绑定上去。
解决:最省事的做法是锁定 jQuery 版本。我在维护这类老页面时,一般把依赖栈整体锁在 jQuery 1.9 到 1.12 区间,确认插件稳定后再谈升级。如果项目里同时存在大量依赖新 jQuery 的组件,那就不能再抱着 1.8.1 不放,应该把校验插件同步升级到 2.x 版本。排查时先看控制台第一条报错位置,基本都能定位到插件源码里调用旧 API 的那一行。
5.2 字段没有 name 属性,规则写了也白写
现象:表单里一个输入框明明在rules里配了规则,校验时却完全不检查,其他字段都正常,只有它永远是空的也能提交。
原因:jquery.validate 从设计上就是按name属性读取字段值和绑定规则的。输入框只有id没有name,插件在初始化扫描时会把rules里的配置对应到<input name="...">,找不到就直接跳过,连错误提示都不会生成。
解决:给每个要校验的控件补上不重复的name。排查时打开浏览器开发者工具,查看表单内控件的name属性是否和rules里的 key 完全一致,包括大小写。还有一种隐蔽情况是页面上有两个相同name的控件,插件只会处理匹配到的第一个,第二个的校验结果会被覆盖。
5.3 动态添加的表单元素不参与校验
现象:点「添加一行」按钮往表格里插入新行,新行里的输入框中空值也能提交,旧行上的校验正常触发。
原因:validate()在初始化时只扫描当时 DOM 中存在的控件,之后动态插入的元素没有对应的规则绑定,插件也不会自动监听。这是 1.8.1 这类老插件里最常见的坑,因为它没有现代框架的响应式机制。
解决:插入新元素后调用rules('add')手动补规则,前一小节的方法直接可用。如果是整块表单重新渲染,更省事的做法是先销毁已有校验器再重新初始化,但要注意销毁逻辑的判断:
var form = $('#dynamicForm'); var validator = form.data('validator'); if (validator) { validator.destroy(); } form.validate({ /* rules, messages */ });逻辑说明:表单的校验器实例会以data('validator')存在元素上,销毁后重新初始化可以避免事件累积。1.8.1 里validator.destroy()方法可用,但不是所有老版本都有,调用前先判断是否存在是最稳妥的。参数说明:重新初始化会重新扫描表单,动态新增的控件也会被纳入规则范围。
5.4 错误提示重复出现,怎么都清不掉
现象:提交一次后,某个字段下面堆了两三条相同或类似的错误提示,字段改对了仍然残留部分红色提示,只有刷新页面才正常。
原因:大多是因为validate()被重复调用,或者errorPlacement逻辑里向同一个容器插入了多次错误元素。还有一个常见来源是页面里同时引入了多个版本的 validate 脚本,两套实例在同一个表单上叠加。
解决:先检查页面里validate()的调用次数,确保只执行一次。如果errorPlacement用的是.append(error),每次校验触发都会追加新元素,应改为先清空容器再插入:
var errorBox = element.closest('.form-item').find('.error-box'); errorBox.empty().append(error);逻辑说明:.empty()会先把容器里残留的错误元素清掉再插入新内容,从根源上避免重复。参数说明:如果已经出现重复绑定,可以在初始化前加上validator.destroy()那段判断,或者直接刷新页面确认问题是否复现,再逐步定位是哪次调用导致的。
5.5 remote 接口返回正确,校验却一直报失败
现象:用户名唯一性校验,输了一个明显没注册过的值,接口返回也正常,但插件还是提示「已被占用」。换个完全不同的值,提示内容跟着变,但结果始终是失败。
原因:1.8.1 的remote规则只认两种返回:纯文本true和纯文本false。接口如果用 JSON 返回{"exists": false},或者返回了字符串"false",插件都会按失败处理。另外remote默认走 GET,且对相同字段值有缓存,前面请求过一次就会复用旧结果。
解决:让服务端接口直接输出布尔字符串。前端如果确实需要传额外参数,把remote写成对象并指定 POST,避免参数过长暴露在 URL 上:
username: { required: true, remote: { url: '/check_username', type: 'POST', data: { username: function() { return $('#username').val(); } } } }逻辑说明:data里的函数写法会在每次校验时重新取值,保证传给接口的是当前输入值。如果你不想让重复校验结果被缓存,可以在data里拼一个时间戳参数,强制每次请求都走服务端。排查时先直接访问接口地址,看返回内容是不是不带引号的true或false,这一步能过滤掉大部分问题。
6. 进阶:配合 AJAX 提交与 remote 校验,让验证结果真正接入业务
6.1 submitHandler 接管 AJAX 提交
大多数现代项目不希望表单用原生提交刷新整个页面,而是校验通过后前端发 AJAX,再根据返回结果做局部提示或跳转。submitHandler就是专门干这个的,它在所有字段都通过校验后执行,接收一个参数即当前表单的 DOM 元素。
$('#orderForm').validate({ rules: { receiver: { required: true }, mobile: { required: true, phoneCN: true } }, messages: { receiver: { required: '请填写收货人' }, mobile: { required: '请填写手机号', phoneCN: '手机号格式不对' } }, submitHandler: function(form) { $.ajax({ url: $(form).attr('action'), type: 'POST', data: $(form).serialize(), dataType: 'json', success: function(res) { if (res.code === 0) { window.location.href = '/order/done'; } else { alert(res.message); } }, error: function() { alert('请求失败,请稍后重试'); } }); return false; } });逻辑说明:submitHandler返回false是为了阻止原生提交和后续默认行为,request发出去之后表单页面不会刷新。$(form).serialize()会把表单内所有带name的控件序列化成查询字符串,和原生提交的参数一致。参数说明:dataType: 'json'要求服务端返回标准 JSON,这里用code + message的约定结构;不同项目的结构不一样,改if (res.code === 0)那行就能接入自家接口。
6.2 remote 做用户名唯一性校验
用户名、手机号、邮箱的重复杂交是后台系统的刚需。在rules里加一条remote,插件就自动在用户离开输入框时发请求问接口这个值是否可用。
$('#registerForm').validate({ rules: { username: { required: true, minlength: 3, remote: { url: '/api/user/check_username', type: 'POST', data: { username: function() { return $('#username').val(); } } } } }, messages: { username: { required: '请输入用户名', minlength: '用户名至少 3 个字符', remote: '该用户名已被注册' } } });界面写法就这么简单,真正要盯住的是服务端返回格式。接口里判断用户名不存在时输出 JSON 字符串"true",存在时输出"false",注意不要用true的 JSON 对象形式,也不要输出额外字段。有一次我把接口写成了返回{ exists: false },结果所有用户名都被判成已被占用,查了一个下午才发现是这里。后来我习惯在接口包里统一封装一个校验方法,约定所有唯一性检查都返回布尔字符串,前端这套配置就再也没出过这类问题。希望帮到你。
本文还有配套的精品资源,点击获取