Bootstrap表单验证功能的实现与常见问题修复

表单这东西,平时大家可能不太在意,但一旦做得不好,用户填到一半就想摔手机走人。特别是用Bootstrap做前端页面的时候,很多人以为把表单样式套上去就万事大吉了,结果一点提交,要么直接跳转刷新,要么报错信息丑得没法看,要么明明填了正确的内容还是提示错误。这篇文章就从实际使用的角度,把Bootstrap表单验证如何实现,以及那些让人头疼的常见问题怎么修复,一次性讲明白。

一、为什么表单验证这么重要

咱们换个场景想一想。你去一个网站注册账号,好不容易把用户名、密码、手机号都填完了,一点注册,页面刷了一下,然后告诉你邮箱格式不对。更气人的是,之前填的内容全没了,得从头再来一遍。这种体验谁遇到谁炸毛。表单验证的作用,就是在用户把数据交出去之前,先在浏览器里帮我们检查一遍。填错了当场指出来,填对了再放行。这既能减少服务器的压力,又能让用户觉得“这个网站还挺聪明的”。Bootstrap本身虽然不提供一套完整的验证逻辑,但它给出了很好的样式基础,比如红色边框、绿色边框、错误提示气泡等等。我们只需要在这些基础上,写一些简单的脚本,就能做出很顺手的验证效果。

二、Bootstrap表单验证的基础玩法

2.1 先搭一个简单的表单

我们先用Bootstrap 5做一个最普通的登录表单。为了让代码能直接跑起来,我们用CDN引入Bootstrap的CSS和JS。这次所有示例都统一使用JavaScript(原生)搭配Bootstrap 5,过程中不使用jQuery,也不用其他验证插件。先看这个基础表单长什么样。

Bootstrap表单验证演示

注意这个form上写了novalidate,表示先关掉浏览器自带的验证提醒。因为浏览器自带的提示气泡长得又丑又没法统一风格,我们更希望自己控制提示方式。

2.2 用Bootstrap自带的表单验证样式

Bootstrap 5官方文档里给了一套“was-validated”的玩法。简单说,当表单提交失败时,我们给form元素加上was-validated这个类,Bootstrap就会自动根据输入框的required、type等属性来显示红色边框和错误文字。我们先看这个最省事的例子。

Bootstrap自带验证样式

用户名至少需要3个字符

年龄需要在18到60之间

这段代码里,checkValidity()是HTML5自带的方法,它会检查每个带required、min、max、type这些属性的控件是否满足规则。只要有一个不满足,就返回false。然后我们给form加上was-validated类,Bootstrap的CSS就会让对应的.invalid-feedback显示出来。注意,每个输入框下面都要放一个.invalid-feedback的div,否则没地方显示错误文字。如果用户填对了,Bootstrap会自动给输入框加绿边框,但默认不会打对勾图标。要是想要那种带对勾的效果,还得再往输入框的父级加.validate之类的类,但咱们先不搞那么花哨,先把基础跑通。

三、自己写验证逻辑,把主动权握在手里

官方这套was-validated虽然省事,但有个大毛病——它只能依赖HTML5内置的规则。比如“两次输入的密码必须一致”、“手机号必须是11位且以1开头”、“验证码只能填写6位数字”,这些规则靠minlength和maxlength根本写不出来。所以实际项目中,我们还得自己写验证逻辑,然后再把Bootstrap的样式套上去。

3.1 验证一个输入框

我们先从最简单的开始:单独验证一个邮箱输入框。当用户离开输入框(blur事件)或者按键盘的时候,我们就检查输入的内容是不是合法的邮箱格式。如果不对,就把输入框的is-invalid类加上,同时显示出错误提示;如果对了,就换成is-valid类,让边框变绿。

单输入框验证

邮箱格式不太对,例:name@domain.com

这里有个小细节:我们用了.invalid-feedback这个类,但默认它是display:none的,只有当输入框兄弟节点中有.is-invalid或者父级有.was-validated时才会显示出来。所以我们在JS里给输入框加了is-invalid类后,Bootstrap就能自动把错误提示显示出来。反过来,如果输入正确,我们会加上is-valid,输入框会变绿,但不会自动加对勾图标。想加对勾图标的话,得在输入框旁边放valid-feedback的div,然后把类换成is-valid后它自己就显示了。这里暂时先不加,后面会说到。

3.2 给表单加上全部验证

一个输入框会了,一整个表单也没啥难的。核心思路就是:在提交的时候,把表单里所有想验证的字段都跑一遍。只要有一个不通过,就不让提交。另外,我们还可以在用户点击提交的那一刻,让所有错误提示一次性冒出来,而不是填一个错一个,这样用户能知道自己到底哪几项填错了。

下面这个例子,模拟一个注册表单,包含姓名、电话、密码、确认密码四个字段。还引入了密码强度提示,算是一点点小加分项。

完整注册表单验证

这段代码看起来长,其实思路很清晰:每个字段的校验都是一个独立的函数,返回true或false。提交的时候把所有函数挨个调用一遍,只要有一个失败就拦住。输入框有边框颜色,错误提示有自己的div,密码有一个小进度条,体验比刚才好很多。

四、常见问题以及修复方法

先别急着高兴,实际开发中你可能会遇到一堆奇怪的问题。这里挑几个最常见的,一个一个说。

4.1 提交时还是跳转了,没拦住

很多人会碰到这种情况:明明写了event.preventDefault(),可表单还是提交了,页面一闪就刷新了。最常见的原因是忘了在form标签上加novalidate。如果不加这个属性,浏览器会先用自己的校验流程来拦一遍,可你监听的那个submit事件可能压根不会触发,因为浏览器在触发submit事件之前就把表单拦下来了。另外还有一个容易忽略的坑:如果你在JS里写form.submit()来触发表单提交,那是不会触发submit事件的,preventDefault自然也就不会执行。正确的做法是,永远让用户点击提交按钮来触发提交,或者用form.requestSubmit(),这个方法才会触发提交事件。

还有一个情况,就是你给form的submit事件绑定了处理函数,但函数里忘了写return false。如果是用onclick属性直接写在HTML里面,就必须写return false才能阻止默认行为。但现在咱们都用addEventListener,就不存在这个问题了。不过为了保险起见,我还是建议在提交按钮的click事件里也做一次校验,双保险。

4.2 验证通过了,但UI没有变化

有时候数据明明是对的,输入框却还是红边框,或者错误提示一直不消失。出现这种问题,通常是因为你给输入框设置了is-invalid类后,在通过验证时确实移除了,但CSS里可能还残留着另外的类,或者是父级容器有.was-validated在捣乱。比如你之前试过Bootstrap自带的验证方式,给form加了was-validated,然后你又自己用is-invalid去控制,这俩类互相打架,结果就乱套了。解决办法很简单:要么完全依赖was-validated,要么完全自己控制is-invalid/is-valid,不要混着用。如果非要用was-validated,那你就得保证所有输入框都符合HTML5校验规则,不然你自己写的错误提示就会跟Bootstrap的默认提示同时出现,看着很乱。

另外还有一个容易忽略的点:如果你给输入框加了disabled属性,Bootstrap就不会对它做任何验证,也不会显示红绿边框。需要验证的输入框一定不要加disabled,要加就加readonly,但这俩语义不同,别搞混。

4.3 提示文字全部挤在一起

当多个字段同时出错时,错误提示会按照文档流一个一个往下排,这个本身没啥问题。但有些人会把.invalid-feedback放进一个.input-group(输入组)里,这时候提示位置就会错乱,甚至会跑到输入框外面。原因很简单,Bootstrap的.invalid-feedback通常要求它紧跟在输入框后面,并且和输入框在同一个父级容器里。如果你为了做图标或按钮把结构改复杂了,可以用.invalid-tooltip来代替,这样提示会以气泡的形式浮在输入框上方。区别在于,.invalid-feedback是静态的块级元素,会挤占布局空间;而.invalid-tooltip是绝对定位的气泡,不会影响其他元素的位置。

@

昵称是必须的

但要注意,如果你把提示放在.input-group里,并且输入框已经有.is-invalid,Bootstrap会自动调整样式,但有时因为父级宽度不够,会导致提示换行。这时候可以考虑用invalid-tooltip,顺便把父级容器设成position: relative。

4.4 自定义校验规则失效

有些人自己写正则,比如检查身份证号、车牌号、银行卡号,结果发现怎么都不生效。大概率是因为正则表达式哪里写错了,比如少了转义符号,或者把test方法用错了地方。更隐蔽的是,你在输入框的oninput事件里做校验,但用户已经输入了内容,却一直没有触发input事件,比如浏览器自动填充表单的时候,就不会触发input事件。这时候你就需要监听change事件,还有一个比较冷门的autofill处理。最简单的办法,是除了绑定input之外,再绑定一下change,并且在页面加载完成后主动跑一次所有校验,这样自动填充的内容也能被发现。

另外一个常见原因,是校验函数返回了true,但紧接着代码里又有个地方把is-invalid加回去了,或者把错误消息赋了一个空字符串但没清除红框。遇到这种“时灵时不灵”的问题,最好的办法是在校验函数末尾用console.log打印一下校验结果,然后一步步排查。不要相信自己的眼睛,多打印几条日志,啥都能看出来。

4.5 动态生成的表单元素验证不生效

现在很多表单不是写死在页面上的,而是根据用户操作动态加出来的,比如点击一下“添加一行”按钮,就生成一个新的输入框。但之前绑定的addEventListener只对页面初始时的那些元素生效。新加进来的输入框没有事件监听,自然就不会被校验。

修复这种动态问题,有两个思路。第一个思路是:每生成一个新元素,就重新给这个元素绑定一次校验事件。这个思路最直白,但代码会显得零散。第二个思路是用“事件委托”,把监听器绑定在form这个父元素上,然后通过e.target判断用户操作的是不是输入框,再做对应处理。事件委托的好处是,不管以后加多少个输入框,都不用重新绑定事件。

下面演示一个用事件委托校验动态行的例子,只截取了核心部分,完整代码在本地就能跑。

动态表单验证示例

动态添加成员

事件委托的关键在于dynamicForm.addEventListener('input', ...),因为input事件会从子元素冒泡到form,所以我们只需要在这里监听一次,不管后来加多少行,都能捕获到。删除按钮也是同理,用memberList监听click事件,然后判断e.target是不是删除按钮。这种方法在写复杂表单时特别省心。

五、应用场景与优缺点

Bootstrap表单验证适合用在管理后台、简单官网、公司内部系统这些项目里。因为这些项目往往不需要特别复杂的交互,界面风格统一,用Bootstrap能快速出活。尤其是配合后端同步验证,前端做一层“温和”的提示,后端再做最后的兜底,这种模式非常常见。

它的优点很明显:第一,学习成本低,Bootstrap的样式类名是公开的,写起来和写普通HTML没啥区别;第二,样式一致,用Bootstrap做的表单不会出现一个红一个蓝的情况;第三,结合原生JavaScript就能做,不用再引入一个庞大的插件,项目构建也轻松。

缺点也存在。首先,Bootstrap本身不包含验证逻辑,需要自己写JS,而且没有现成的国际化错误消息,提示文字都得自己写。其次,对于特别复杂的表单,比如多步骤、联动判断、根据接口返回值动态更新错误,这些事用Bootstrap做起来不够爽,需要写很多额外代码。另外,如果页面已经用了别的UI库,再塞进Bootstrap,样式冲突会让你怀疑人生。所以,选不选Bootstrap做验证,得先看看你的项目是不是已经引入了Bootstrap。如果已经引入了,那就放心的用;如果完全没用过,只是为了表单验证而引入一个大CSS框架,那不太划算。

六、注意事项

在实际开发中,有几个细节一定要记牢。

第一,前端验证永远不能代替后端验证。用户可以在浏览器里禁用JavaScript,甚至自己拼接口提交假数据。你前端口头说“邮箱格式不对”,并不代表后端不接收这封邮件。后端必须再做一次完整的数据校验,这也是行业共识。

第二,错误提示文案要写人话。别写“非法字符”“格式不合法”这种冷冰冰的话,换成“密码只能填数字和字母”“手机号要11位”这种大家一看就懂的表达。还有,提示要出现在输入框附近,不要放在页面最底部,让用户来回看,眼睛会很累。

第三,注意校验时机。不要在用户填第一个字母的时候就弹红框,那样会把人吓跑。一般做法是:输入框还没被碰过的时候,不做多余的提示;等用户输入了一部分,再开始实时校验;等用户离开输入框,再给最终结论。这就是所谓的“模糊校验”和“严格校验”的区别。你可以为每个输入框设定一个touched状态,第一次失去焦点之后,再开始实时校验。

第四,当表单里有多个必填项时,提交按钮点击后,最好把第一个出错的输入框滚动到视野中,并且让它自动获得焦点。这样用户可以立刻知道从哪里开始改。用Bootstrap做这个很简单,就是firstInvalidElement.focus({preventScroll: false}),再配合scrollIntoView。

第五,需要考虑浏览器兼容性。Bootstrap 5对IE的兼容性很差,如果你的项目还需要支持IE11,那建议用Bootstrap 4,或者干脆自己写一套验证逻辑。另外,checkValidity()方法在所有现代浏览器里都有,但在一些老旧的webview里可能会出幺蛾子,保险起见可以用try-catch包一层,或者自己写一个简单的校验函数替代。

第六,动态生成的表单元素,一定要记得用事件委托或者重新绑定事件,不然就会像上面那样,新加的行根本不参与校验。还有,动态行删除的时候,也要检查一下是否留下了被移除元素的错误提示,不然界面上会残留红框。

七、文章总结

表格里那一个小小的验证框,看似不起眼,但真的能决定一个用户愿不愿意在你的网站上多停留几分钟。通过这篇文章,我们把Bootstrap表单验证的两种路线捋清楚了:一种是直接依赖Bootstrap自带的was-validated样式加上HTML5的验证属性,适合简单场景;另一种是用JavaScript自己控制is-invalid和is-valid,适合需要自定义规则的场景。同时也把提交拦不住、UI不更新、动态内容失效这些坑点都填了。

做表单验证这件事,本质上不是在跟技术较劲,而是在跟用户沟通。你要让用户觉得,填表是有指引的,是不容易被卡住的。哪怕他填错了,你也能温柔地告诉他哪里错了、该怎么改。只要能做到这一步,你手里的Bootstrap就真正派上用场了。

最后再说一句:无论你用了多漂亮的验证效果,记得后端一定要再做一次验证。前端和后端,一个是门口的保安,一个是仓库里的保管员,都存在才安心。希望你下一次做表单的时候,能稳稳当当的,不再被这些乱七八糟的小问题绊住脚。

“夜泊金陵”十大精品夜游线路发布
景云名字寓意和解析