银行卡号格式化必须用 JavaScript 的 oninput 事件监听,配合 replace 清除非数字、slice 截断、match 分组、手动修复光标位置,并使用 inputmode="numeric" 和 maxlength="19",真实卡号严禁明文暴露于 DOM。

银行卡号格式化不能靠 CSS 或纯 HTML 实现,必须用 JavaScript 监听输入并实时处理;否则要么光标乱跳,要么粘贴失效,要么移动端直接崩。
oninput 事件是唯一靠谱的入口
用 keyup 或 change 都会漏掉粘贴、拖拽、语音输入等场景,oninput 是浏览器原生支持的、覆盖所有输入方式的事件。iOS 微信、安卓 WebView、Chrome、Safari 全部兼容。
- 必须先用
.replace(/\D/g, '')清掉所有非数字字符——中文数字、全角空格、短横线、字母都会破坏分组逻辑 - 卡号最多 16 位,超长要截断:
v = v.slice(0, 16),不能等用户输完再提示 - 分组用
v.match(/.{4}/g) || [],比循环拼接更安全,空字符串也不会报错 - 不要直接赋值
el.value = segments.join(' '),否则安卓微信里光标必然跳到末尾
光标位置必须手动修复
用户在中间修改时(比如把 “1234 5678 9012 3456” 改成 “1234 5678 9012 3457”),直接重设 value 会导致光标跑到最后,体验极差。
- 只在用户光标位于末尾且当前长度是 4 的整数倍时才触发修复:
if (v.length % 4 === 0 && el.selectionStart === el.value.length) - 用
setSelectionRange(el.value.length - 1, el.value.length - 1)把光标卡在空格前一位 - 这个判断不是可选优化,是 iOS 和部分安卓 WebView 的刚需
inputmode="numeric" 比 type="number" 更稳
type="number" 在很多安卓机型上禁止输入空格,直接让分隔失效;inputmode="numeric" 只控制软键盘类型,不限制字符输入,是目前最平衡的选择。
立即学习“前端免费学习笔记(深入)”;
-
maxlength="19"是硬性要求:16 位数字 + 3 个空格,多一位都可能触发浏览器自动纠错 - 别用
pattern做实时校验——它只在表单提交时触发,且写成\d{4} \d{4} \d{4} \d{4}会让用户输到第 5 位就标红 - 如果后端需要原始卡号,建议存进
data-oral属性,而不是靠 JS 再去.replace(/\s/g, ''),避免多次处理出错
脱敏显示和真实值必须严格分离
页面上渲染的永远只能是 **** **** **** 1234 这类掩码,真实卡号绝不能出现在 DOM 属性、注释、data- 属性或 innerHTML 中——审查元素一眼可见等于裸奔。
- 真实值只保留在 JS 变量或加密后的
localStorage里,且需配合Web Crypto API加密 - 用
parseInt(cardNumber)转数字会丢精度,16 位以上卡号超出Number.MAX_SAFE_INTEGER,末几位变 0 - “设为默认”这类操作,必须同步更新 JS 数据层的
defaultCardId,不能只改 class
真正上线时,前端连卡号明文都不该碰;这里说的全是本地原型或内部工具的底线做法——离生产环境还有至少三道后端网关的距离。



















