如何制作一个HTML PIN码输入框?
- 内容介绍
- 文章标签
- 相关推荐
本文共计862个文字,预计阅读时间需要4分钟。
纯HTML无法实现真正意义上的PIN码输入框(即自动聚焦、限制只输入数字、隐藏内容、逐位跳转等)。必须配合JavaScript才能完成。
为什么不能只用 type="password"?
它会隐藏所有字符,但 PIN 码通常需要「显示位数」(如 ●●●●)且不允许字母/符号;更重要的是,它不阻止粘贴非数字内容,也无法控制光标跳转逻辑。
- 用户粘贴
"abc123"会静默接受前几位,导致长度错乱 - 长按输入法可能触发字母候选,
inputmode="numeric"仅是提示,不强制 - 移动端软键盘仍可能弹出完整键盘(尤其 iOS Safari 对
type="password"+inputmode支持不稳定)
用 type="tel" + inputmode="numeric" 能行吗?
这是最轻量的“够用”方案,适合对体验要求不高的场景,但需主动拦截非法输入。
<input type="tel" inputmode="numeric" pattern="[0-9]*" maxlength="6">-
pattern和maxlength仅用于表单校验,不阻止实时输入 - 必须加 JS 监听
input事件,用value = value.replace(/\D/g, '')实时清洗 - iOS 上
inputmode="numeric"可能被忽略,需搭配pattern="[0-9]*"提高触发概率
如何实现带跳转的 4 位 PIN 输入(每个 <input> 单独一位)?
这是体验最好的方案,但 DOM 结构和事件逻辑稍复杂。核心是:每个 <input> 只允许 1 位数字,输入后自动 focus 下一个,删除时回退上一个。
立即学习“前端免费学习笔记(深入)”;
- 用 4 个
<input type="text" inputmode="numeric" maxlength="1">并排,视觉上合并边框 - 监听每个的
input事件:若值非数字,清空;若填入则nextElementSibling?.focus() - 监听
keydown:捕获Backspace和Delete,当前为空时previousElementSibling?.focus() - 禁止粘贴:
onpaste="event.preventDefault()",或监听paste事件并event.clipboardData.getData('text').replace(/\D/g,'').slice(0,4)分发到各框
容易被忽略的关键点
PIN 输入不是“做出来就行”,真实场景里这些细节直接决定是否可用:
- 屏幕阅读器支持:给每格加
aria-label="第1位PIN",整体容器加role="group"和aria-label="请输入6位PIN码" - 失焦时校验:用户点击别处,要检查是否填满,未满需 focus 第一个空位(不能只靠 submit 校验)
- 密码管理器兼容性:Chrome 会尝试填充
type="password",但不会填type="tel";若需支持自动填充,得用type="password"+ JS 拦截非数字 + 显式声明autocomplete="one-time-code" - iOS Safari 的 focus 延迟:调用
focus()后立即select()可能无效,需包裹在setTimeout(() => { input.select() }, 0)
本文共计862个文字,预计阅读时间需要4分钟。
纯HTML无法实现真正意义上的PIN码输入框(即自动聚焦、限制只输入数字、隐藏内容、逐位跳转等)。必须配合JavaScript才能完成。
为什么不能只用 type="password"?
它会隐藏所有字符,但 PIN 码通常需要「显示位数」(如 ●●●●)且不允许字母/符号;更重要的是,它不阻止粘贴非数字内容,也无法控制光标跳转逻辑。
- 用户粘贴
"abc123"会静默接受前几位,导致长度错乱 - 长按输入法可能触发字母候选,
inputmode="numeric"仅是提示,不强制 - 移动端软键盘仍可能弹出完整键盘(尤其 iOS Safari 对
type="password"+inputmode支持不稳定)
用 type="tel" + inputmode="numeric" 能行吗?
这是最轻量的“够用”方案,适合对体验要求不高的场景,但需主动拦截非法输入。
<input type="tel" inputmode="numeric" pattern="[0-9]*" maxlength="6">-
pattern和maxlength仅用于表单校验,不阻止实时输入 - 必须加 JS 监听
input事件,用value = value.replace(/\D/g, '')实时清洗 - iOS 上
inputmode="numeric"可能被忽略,需搭配pattern="[0-9]*"提高触发概率
如何实现带跳转的 4 位 PIN 输入(每个 <input> 单独一位)?
这是体验最好的方案,但 DOM 结构和事件逻辑稍复杂。核心是:每个 <input> 只允许 1 位数字,输入后自动 focus 下一个,删除时回退上一个。
立即学习“前端免费学习笔记(深入)”;
- 用 4 个
<input type="text" inputmode="numeric" maxlength="1">并排,视觉上合并边框 - 监听每个的
input事件:若值非数字,清空;若填入则nextElementSibling?.focus() - 监听
keydown:捕获Backspace和Delete,当前为空时previousElementSibling?.focus() - 禁止粘贴:
onpaste="event.preventDefault()",或监听paste事件并event.clipboardData.getData('text').replace(/\D/g,'').slice(0,4)分发到各框
容易被忽略的关键点
PIN 输入不是“做出来就行”,真实场景里这些细节直接决定是否可用:
- 屏幕阅读器支持:给每格加
aria-label="第1位PIN",整体容器加role="group"和aria-label="请输入6位PIN码" - 失焦时校验:用户点击别处,要检查是否填满,未满需 focus 第一个空位(不能只靠 submit 校验)
- 密码管理器兼容性:Chrome 会尝试填充
type="password",但不会填type="tel";若需支持自动填充,得用type="password"+ JS 拦截非数字 + 显式声明autocomplete="one-time-code" - iOS Safari 的 focus 延迟:调用
focus()后立即select()可能无效,需包裹在setTimeout(() => { input.select() }, 0)

