如何实现动态创建的OTP输入框自动聚焦到下一个字段

13次阅读

如何实现动态创建的OTP输入框自动聚焦到下一个字段

本文讲解为何otp输入框的change事件无法触发自动聚焦,以及如何改用input或keyup事件来正确实现数字输入后自动跳转到下一个输入框的功能。

在构建6位一次性密码(OTP)输入组件时,一个常见需求是:用户在某个输入框中输入一位数字后,焦点自动移至下一个输入框。然而,若使用 change 事件监听值变化,会发现该逻辑几乎从不生效——因为 change 事件仅在输入框失去焦点(blur)且内容发生过修改时才触发,而非实时响应每一次输入。

这正是原代码失效的根本原因:

input.onchange = (e) => { /* ... */ }; // ❌ 错误时机:用户尚未离开当前输入框,change 不会触发

✅ 正确做法是监听 input 事件(推荐)或 keyup 事件:

  • input 事件在 每次变更时立即触发(包括粘贴、删除、键盘输入),语义最准确;
  • keyup 事件则在按键释放后触发,适合需区分按键类型的场景(如过滤非数字键)。

以下是修复后的核心逻辑(已适配动态创建流程):

for (let i = 0; i < OTP_LENGTH; i++) {   const input = document.createElement('input');   input.type = 'text'; // ⚠️ 改为 text 更稳妥(number 类型在部分浏览器中可能触发 blur)   input.maxLength = 1;   input.dataset.otpPos = i;   input.className = 'otp-input';    // ✅ 使用 input 事件替代 onchange   input.addEventListener('input', function(e) {     const target = e.target;     const pos = parseInt(target.dataset.otpPos, 10);      // 确保只输入单个数字(可选增强)     target.value = target.value.replace(/[^0-9]/g, '').slice(0, 1);      if (pos < OTP_LENGTH - 1 && target.value) {       // 清空并聚焦下一个输入框(避免重复触发)       const nextInput = textInputs[pos + 1];       nextInput.value = '';       nextInput.focus();     }   });    // 可选:支持退格键回退(提升体验)   input.addEventListener('keydown', function(e) {     if (e.key === 'Backspace' && !this.value && this.previousElementSibling) {       e.preventDefault();       this.previousElementSibling.focus();       this.previousElementSibling.select();     }   });    otpContainer.appendChild(input);   textInputs.push(input); }

⚠️ 注意事项:

  • 避免重复 focus() 调用:确保 nextInput.focus() 前不触发其他干扰逻辑(如多次绑定事件);
  • 禁用 type="number":因其在移动端可能引发软键盘异常、自动 blur 或值校验延迟,推荐统一用 type="text" + 正则过滤;
  • ID 唯一性:原代码中所有输入框 id="otp-input" 违反 html 规范,应改用 data-* 属性或 class 定位;
  • 移动端兼容性:input.focus() 在 ios safari 中需在用户手势上下文中调用(本例满足),但避免在异步回调(如 setTimeout)中调用。

总结:OTP 自动聚焦失败的本质是事件选型错误。将 change 替换为 input,配合合理的值清理与边界判断,即可稳定实现“输完即跳”的交互体验。

text=ZqhQzanResources