应监听 animationstart、轮询值变化、focusin/focusout 组合来精准捕获自动填充时机;延迟恢复 type、主动聚焦并设光标位置、按平台差异微调焦点逻辑;明文切换需记录状态、避免 blur 中还原 type。

移动端密码自动填充(如 iOS 钥匙串、Android Chrome 密码管理器、微信/支付宝内置密码库)会绕过常规用户操作流程,直接修改 input 值并触发一系列非标准的 focus/blur 事件序列。这导致前端常出现「刚填完密码就失焦」「切换明文时闪退」「blur 后立即 focus 失败」等问题。关键不是阻止自动填充,而是预判它的行为节奏,用可落地的方式稳住焦点流。
识别自动填充发生的准确时机
不能依赖 input 或 change 事件——Safari 粘贴密码时 event.data 为 null,Chrome 可能批量触发多次 input。应统一改用:
- 监听
animationstart事件:iOS 钥匙串填充时会触发webkit-text-security切换动画,可作为填充开始信号 - 轮询检测值变化:对 password 字段设
setTimeout(() => { if (el.value && !wasFilled) { handleAutoFill(); } }, 100),兼容所有内核 - 监听
focusin+focusout组合:比focus/blur更可靠,尤其在 X5 内核中能捕获钥匙串弹出后的真焦点流转
防止 blur 后焦点丢失或键盘收起
自动填充后系统常伴随一次隐式 blur(例如 iOS 钥匙浮层收起),若此时你又调 el.blur() 或在 blur 回调里切回 type="password",极易造成键盘闪退或光标消失:
- 禁用「blur 立即切 type」逻辑:把
type="password"的恢复延迟到setTimeout(() => el.type = "password", 0) - 填充完成后主动聚焦并保持光标位置:
el.focus(); el.setSelectionRange(el.value.length, el.value.length); - 对微信/X5 等环境,加一个「焦点保险」:填充后立即创建并聚焦一个隐藏
input[type="text"](position: absolute; width: 0; height: 0;),再快速切回密码框,骗过内核拦截
适配不同平台的填充后焦点行为差异
iOS、Android Chrome、微信、支付宝各自填充完成后的焦点状态不一致,需按平台微调:
- iOS Safari:填充后通常仍保持 focus 状态,但键盘可能已收起 → 调用
el.focus()会重新唤起键盘,建议仅在用户点击「登录」等明确操作后再聚焦 - Android Chrome:填充后多数情况未 focus,需手动
focus();但部分国产 ROM(华为、小米)会在填充后自动 focus,重复调用会报错 → 先检查document.activeElement === el再决定是否聚焦 - 微信 Android(X5 内核):填充后
focus()常静默失败 → 改用el.click()模拟一次真实点击,或绑定到按钮的touchstart回调中执行
明文切换与自动填充共存的处理要点
「显示/隐藏密码」按钮和自动填充容易冲突,尤其在用户先点「显示」再触发钥匙串时:
- 按钮点击时,先记录当前
type和value,再切换;填充发生时,优先以最新value为准,不覆盖用户已输入内容 - 避免在
blur里还原 type:改为监听focusout+focusin组合,判断是否由密码浮层触发(可通过event.relatedTarget是否为钥匙串 DOM 元素粗略判断) - 微信中按钮失效?确保它用
,父容器无pointer-events: none,且 z-index > 1,X5 对 div 按钮的事件穿透支持极差











