原生 type="email" 仅作前端快速过滤,无法拦截 me@localhost 等无效邮箱;需在 submit 事件中 trim、checkvalidity、清理不可见字符并配合 setcustomvalidity 统一校验。

原生 type="email" 能拦住明显错误(比如缺 @ 或没点),但拦不住 me@localhost、admin@mail. 这类看似合法实则无效的邮箱;它只是前端体验层的“快速过滤”,绝不能当作验证终点。
为什么 type="email" + required 还会提交成功
常见绕过方式有三种:
- 用户输入前后带空格,如
" user@example.com "—— 浏览器不自动trim(),checkValidity()返回true,但后端解析可能失败 - 表单加了
novalidate属性,整个原生校验被禁用 - JS 直接调用
form.submit(),跳过了触发checkValidity()的默认流程
解决办法是在 submit 事件里手动处理:
const emailInput = document.querySelector('input[type="email"]');
emailInput.value = emailInput.value.trim();
if (!emailInput.checkValidity()) {
emailInput.reportValidity();
e.preventDefault();
}
pattern 正则怎么写才不踩 Safari 和 iOS 的坑
Safari 对 pattern 支持不稳定,尤其遇到大小写混用或开头结尾锚定符时容易失效。推荐写法是:
- 全小写正则,加
i标志不如直接写小写,更稳妥 - 去掉
^和$——pattern默认锚定首尾 - 避免 RFC 级别复杂正则,它们在
pattern中基本不生效,还可能让 iOS Safari 忽略整个属性
可用的 pattern 值:
pattern="[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,}$"
注意:这个正则不接受中文、全角符号、连续点号(user..name@domain.com)或单字母顶级域(user@domain.c)。
JS 手动校验时,checkValidity() 和正则谁先谁后
先调 checkValidity(),再补正则。因为前者已覆盖:required、空值、基础结构(@ 和 .)、type="email" 内置规则;重复用 JS 正则反而可能漏掉这些约束。
典型错误:
- 在
input事件里每敲一个字就跑一遍正则 → 卡顿且体验差 - 没等用户输完(比如刚敲
a@)就标红 → 干扰输入节奏 - 后端返回格式错误后,只改提示文字,没调
setCustomValidity("...")→ 下次checkValidity()仍返回true
正确做法是:在 submit 时统一校验,出错后调用:
emailInput.setCustomValidity("邮箱格式不正确");
emailInput.reportValidity();
// 用户修改后,需立刻清空:
emailInput.setCustomValidity("");
最容易被忽略的是不可见字符:用户粘贴邮箱时可能带零宽空格(U+200B)、软连字符(U+00AD)等,它们在输入框里看不见,却会让 checkValidity() 返回 false。需要在 trim 后额外清理:
emailInput.value = emailInput.value .trim() .replace(/[\u200B-\u200D\uFEFF]/g, "");
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











