HTML原生pattern仅支持正则匹配,无法校验身份证号等含算法逻辑的字段;必须用JavaScript在blur时执行加权求和+mod11校验,且后端须重复验证。
pattern 做前端简单校验,但别信它能防错HTML 原生 pattern 只能做正则匹配,对身份证号这种有算法校验逻辑的字段,pattern 顶多拦住明显乱输的(比如纯字母、位数不对),但无法验证最后一位校验码是否正确。浏览器不会执行加权求和 + mod 11 这套逻辑。
常见错误是写成:<input pattern="^d{17}[dXx]$"> —— 这连 15 位旧号码都不支持,更别说校验码了。
0-9 或 X(大小写都允许)[7,9,10,5,8,4,2,1,6,3,7,9,10,5,8,4,2] 与前 17 位相乘求和,再对 11 取模,结果对应校验码表 ['1','0','X','9','8','7','6','5','4','3','2']
pattern 只建议作为辅助提示,比如:pattern="^d{17}[dXx]$" 配合 title="请输入18位身份证号",降低用户误输概率onblur 或 addEventListener('blur') 触发 JS 校验真实校验必须靠 JavaScript,在用户离开输入框时执行。不要用 oninput 实时校验——每打一个字都算一次校验码,体验卡顿且无必要。
示例关键逻辑:
立即学习“前端免费学习笔记(深入)”;
function validateIdCard(id) { const reg = /^[1-9]d{5}(18|19|20)d{2}(0[1-9]|1[0-2])(0[1-9]|[12]d|3[01])d{3}[dXx]$/; if (!reg.test(id)) return false; const factor = [7,9,10,5,8,4,2,1,6,3,7,9,10,5,8,4,2]; const checkCode = ['1','0','X','9','8','7','6','5','4','3','2']; const sum = id.slice(0, 17).split('').reduce((acc, cur, i) => acc + parseInt(cur) * factor[i], 0); return checkCode[sum % 11].toUpperCase() === id[17].toUpperCase();}
parseInt() 转数字,否则字符串相乘会出错id[17].toUpperCase()
任何前端校验都能被绕过——禁用 JS、手动改 DOM、curl 直接 POST。所以 validateIdCard() 函数必须在服务端用相同逻辑再跑一遍。
re.match() + 手动加权计算400 Bad Request,错误信息里不要暴露校验细节(比如“第18位应为X”),避免被用于枚举攻击inputmode="numeric" 和 inputmode="text" 的取舍身份证号不能用 type="number",因为末尾 X 会导致输入被截断或报错。但用 type="text" 默认唤起全键盘,体验差。
<input type="text" inputmode="numeric" pattern="[0-9Xx]*">
inputmode="numeric" 在 iOS/Android 大部分浏览器中会唤起数字键盘,用户输完再手动切字母键输 X
pattern="[0-9Xx]*" 是为了让 iOS 在数字键盘上显示 X 键(部分版本支持)maxlength="18":15 位老证虽少,但加了会直接卡死输入,不如让 JS 校验后提示前端校验只是减少无效提交,真正可靠的只有后端那一次计算。很多人写了正则就以为万事大吉,结果上线后发现“11010119900307299Q”这种明显错误的号也能过——因为没算校验码。