autocomplete="one-time-code" 静默失效的根本原因是浏览器otp填充链路断裂,需满足表单提交历史、dom稳定性、正确type与name属性、https环境及短信格式四点闭环。

autocomplete="one-time-code" 不是加了就生效的开关,而是浏览器识别 OTP 填充链路中的一个必要环节——漏掉任意一环,它就静默失效。
为什么写了 autocomplete="one-time-code" 却没反应
常见错误现象:输入框属性写对了,短信也收到了,但浏览器毫无提示。根本原因不是“不支持”,而是识别链路断裂:
- 表单没提交过:Chrome/Edge 要求用户**此前在该域名下成功提交过一次含该 input 的 form**,否则不触发填充逻辑
- input 被动态替换:React/Vue 渲染后 DOM 节点重建,原
autocomplete="one-time-code"属性丢失(哪怕值一样,节点不同就不认) - type 用错:用了
type="number"或type="search",浏览器直接忽略;必须是type="text"或type="tel" - 同一表单里写了多个
autocomplete="one-time-code":只认第一个,其余无效 - 页面不是 HTTPS:所有现代浏览器强制要求安全上下文,HTTP 下完全禁用
type="tel" 和 type="text" 怎么选
移动端体验差异明显,选错会直接导致键盘弹出异常或填充失败:
-
type="tel"更推荐:自动唤起数字键盘、禁用拼写检查、兼容 WebOTP API,且 Safari/iOS 对其填充识别率更高 -
type="text"也可用,但必须配inputmode="numeric"(注意:不能和type="tel"同时用,会冲突) - 绝对避免
type="number":iOS 键盘带小数点和上下箭头,Android 可能触发非预期格式校验 - name 属性要语义化:用
name="otp"或name="code",别用name="input-1"这类无意义命名
WebOTP API 和 autocomplete="one-time-code" 是什么关系
它们不是互斥方案,而是分场景协作的两套机制:
- Safari(16.4+):原生监听短信 +
autocomplete="one-time-code"→ 自动填充,无需 JS 调用 - Chrome/Edge(108+):依赖 WebOTP API 主动拉取,但填充目标仍由
autocomplete="one-time-code"指定 - 调用
navigator.credentials.get({ signal, ... })必须在用户手势后(如按钮点击),否则报NotAllowedError - 短信格式必须严格匹配:以【品牌名】开头 + 6 位纯数字 + 域名(如
【MyApp】123456 example.com),缺一不可 - transport: ['sms'] 是必填项,漏掉会导致返回
null
容易被忽略的 DOM 和事件细节
即使结构全对,时机和事件监听方式不对,依然拿不到值:
- 不要监听
change:Safari autofill 不触发该事件;改用input事件 + 防抖(setTimeout300ms) - 别依赖
e.target.value立即读取:React/Vue 响应式系统可能还没同步,建议用requestAnimationFrame下一帧再取 - 提交后立刻聚焦:在 form 的
submit回调里执行input.focus(),告诉浏览器“现在要填这个” - 别设初始
value或用 JS 清空后再聚焦:会打断浏览器的填充上下文识别
真正跑通的关键,不在属性本身,而在表单提交历史、DOM 稳定性、短信格式与用户交互时机这四点闭环。少一个,autocomplete="one-time-code" 就只是个静态字符串。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











