
本文介绍如何使用原生 javascript 实现 otp/pin 多位输入框的联动控制:实时捕获各单字符输入框内容,自动拼接为完整字符串,并同步写入用户名与密码两个目标字段,支持键盘输入、粘贴、退格等交互行为。
本文介绍如何使用原生 javascript 实现 otp/pin 多位输入框的联动控制:实时捕获各单字符输入框内容,自动拼接为完整字符串,并同步写入用户名与密码两个目标字段,支持键盘输入、粘贴、退格等交互行为。
在构建登录或验证码输入界面时,常需将多个单字符输入框(如 6 位 OTP)的输入值自动聚合为一个完整字符串,并同步填充至用户名和密码字段(二者值相同)。传统 jQuery 方案易出现事件冲突、焦点管理混乱等问题;而采用现代原生 JavaScript 可实现更稳定、可维护性更强的解决方案。
以下是一个完整、健壮的实现:
✅ 核心逻辑说明
- 使用 input 事件监听每个 PIN 输入框的变更,实时拼接所有 value;
- 利用 reduce() 高效聚合字符数组,生成完整 PIN 字符串;
- 自动同步该字符串至 name="username" 和 name="password" 的输入框;
- 支持智能焦点跳转(输入后自动进入下一格)、退格回溯(Backspace 时聚焦前一格)及粘贴解析(自动过滤空格、连字符并按序填充)。
? 完整示例代码
<meta charset="UTF-8"><title>PIN 合并输入示例</title><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.2/dist/css/bootstrap.min.css"><style>
.flex { display: flex; gap: 8px; }
.pin > input {
text-align: center;
width: 2.5rem;
height: 2.5rem;
font-size: 1.2rem;
border: 1px solid #ced4da;
border-radius: 4px;
outline: none;
transition: border-color 0.2s;
}
.pin > input:focus { border-color: #007bff; box-shadow: 0 0 0 3px rgba(0,123,255,.25); }
</style><div class="row">
<div class="col-md-3">
<div class="otpCont flex">
<form id="pinForm">
<h4 class="mb-3">请输入 6 位 PIN</h4>
<div class="pin mb-3">
<input type="text" name="pin[]" maxlength="1" autocomplete="off" required autofocus><input type="text" name="pin[]" maxlength="1" autocomplete="off" required><input type="text" name="pin[]" maxlength="1" autocomplete="off" required><input type="text" name="pin[]" maxlength="1" autocomplete="off" required><input type="text" name="pin[]" maxlength="1" autocomplete="off" required><input type="text" name="pin[]" maxlength="1" autocomplete="off" required>
</div>
<div class="mb-2">
<label class="form-label">用户名(自动同步):</label>
<input type="text" name="username" class="form-control" readonly>
</div>
<div class="mb-3">
<label class="form-label">密码(自动同步):</label>
<input type="text" name="password" class="form-control" readonly>
</div>
<button type="submit" class="btn btn-primary w-100">提交</button>
</form>
</div>
</div>
</div>
<script>
// DOM 工具函数
const els = (sel, par = document) => par.querySelectorAll(sel);
const el = (sel, par = document) => par.querySelector(sel);
// 获取目标字段
const elUN = el(`[name="username"]`);
const elPW = el(`[name="password"]`);
// 处理每组 PIN 输入框(支持多组扩展)
els(".pin").forEach((group) => {
const inputs = [...els(`[name="pin[]"]`, group)];
const len = inputs.length;
const handlePaste = (ev) => {
ev.preventDefault();
const clip = ev.clipboardData.getData('text');
const pin = clip.replace(/[\s\-]/g, ''); // 清除空格与短横线
const chars = [...pin];
inputs.forEach((inp, i) => (inp.value = chars[i] ?? ''));
inputs[Math.min(len - 1, chars.length - 1)]?.focus();
};
const handleInput = () => {
const pinValue = inputs.reduce((acc, inp) => acc + inp.value, "");
elUN.value = pinValue;
elPW.value = pinValue;
};
const handleKeyDown = (ev) => {
const idx = inputs.indexOf(ev.currentTarget);
if (ev.key === "Backspace" && !ev.currentTarget.value && idx > 0) {
inputs[idx - 1].focus();
}
};
const handleKeyPress = (ev) => {
const idx = inputs.indexOf(ev.currentTarget);
if (ev.key.length === 1 && idx < len - 1 && ev.currentTarget.value) {
inputs[idx + 1].focus();
}
};
// 绑定事件
inputs.forEach(inp => {
inp.addEventListener("paste", handlePaste);
inp.addEventListener("input", handleInput);
inp.addEventListener("keydown", handleKeyDown);
inp.addEventListener("keypress", handleKeyPress);
});
});
</script>
⚠️ 注意事项
- 所有 PIN 输入框必须具有相同 name="pin[]" 属性,便于统一选择;
- maxlength="1" 是关键,防止用户输入多字符破坏结构;
- 使用 readonly 属性保护用户名/密码字段不被手动编辑(如需可改为 disabled,但注意其值不会随表单提交);
- 粘贴逻辑已兼容常见格式(如 "123 456"、"123-456"),自动清洗后按顺序填充;
- 若需支持移动端软键盘自动跳转,建议补充 inputmode="numeric" 与 pattern="[0-9]*" 提升体验。
该方案完全脱离 jQuery 依赖,语义清晰、性能高效,适用于各类 OTP、PIN、验证码等场景,具备良好的可复用性与可扩展性。











