必须调用event.preventdefault()阻止表单默认提交,同时手动调用reportvalidity()触发浏览器原生校验;formdata需后置清洗空格与零宽字符;提交成功后再调用form.reset()清空表单;所有前端校验与清洗仅优化体验,后端仍须独立验证。

event.preventDefault() 是必须调用的,否则表单会绕过 JS 直接提交并刷新页面——哪怕你写了校验逻辑、加了 onsubmit、甚至绑了 click 事件,只要没拦住这个默认行为,就等于没拦截。
为什么 submit 事件里不调用 reportValidity() 就算白拦
浏览器原生校验(required、type="email"、pattern)不会自动触发,只在用户点击提交或显式调用时生效。单纯 e.preventDefault() 只是卡住提交动作,字段是否为空、邮箱格式对不对,它一概不管。
常见错误现象:前端看似“拦住了”,但后端收到空字符串或非法邮箱;用户没看到任何提示,以为表单坏了。
- 必须手动调用
form.reportValidity()—— 它会弹出浏览器默认气泡提示,且返回布尔值 - 如果想静默校验(比如配合自定义 UI),改用
form.checkValidity(),但得自己写错误反馈逻辑 - 对自定义规则(如手机号、敏感词),需配合
input.setCustomValidity("提示文字"),否则checkValidity()永远返回true
FormData vs 手动取值:清洗时机和空格陷阱
用 new FormData(form) 看似省事,但它拿到的是原始 input.value,包括首尾全角空格、零宽字符(\u200b)、不间断空格(\u00a0)——这些 trim() 都清不掉。
使用场景:表单字段多、含文件上传、需保持键名与 name 属性一致时,FormData 更稳妥;但清洗必须在转换成对象后做,不能依赖它自动净化。
- 安全清洗正则:
value.replace(/^[\s\uFEFF\u200B\u00A0]+|[\s\uFEFF\u200B\u00A0]+$/g, '') - 不要在
input事件里实时value = value.trim(),会破坏光标位置 - 密码字段慎用
trim()—— 用户可能真设了带空格的密码,UI 上应明确提示“首尾空格不可见” - 富文本(
textarea)保留换行,但服务端仍需过滤 XSS 风险内容,不能只靠前端清洗
提交后清空表单:别用 type="reset" 按钮
type="reset" 会清空但不提交,跟需求完全相反。正确做法是在拦截后的异步提交成功回调里调用 form.reset()。
容易踩的坑:AJAX 提交失败时也执行了 reset(),用户输入全丢;或者忘记处理 disabled 或 readonly 字段,它们不会被 reset() 清空。
- 只在
fetch().then()成功分支里调用form.reset() - 若字段被设为
disabled,先临时启用再reset(),或手动清空其value - 用
form.querySelectorAll('input, select, textarea')遍历清理更可控,尤其含动态字段时
最常被忽略的一点:所有前端清洗、校验、拦截,都只是用户体验层的优化。curl、禁用 JS、抓包重放,都能绕开——后端收到的每个字段,仍要独立做清洗、长度截断、XSS 过滤、敏感词检测。前端拦得再严,也不代表数据干净了。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











