autofocus仅在html初始解析时对首个符合条件的原生表单元素一次性生效,动态插入或spa路由切换后需用focus()手动聚焦,并确保元素可见、可聚焦且在用户手势上下文中。

autofocus属性只在HTML初始解析时生效
它不是“写上就聚焦”的开关,而是浏览器在加载页面、解析原始 HTML 时对第一个符合条件的元素做的一次性处理。只要元素在初始 HTML 中存在、未被 JS 动态插入,且满足可聚焦条件,就会触发。
常见错误现象:autofocus 写了但没反应,大概率是因为元素是 Vue/React 渲染出来的、或通过 innerHTML 插入的——这些场景下浏览器早已完成解析,属性形同虚设。
-
autofocus是布尔属性,不赋值:<input type="text" autofocus>✅;<input autofocus="true">❌(冗余) - 一个页面中多个
autofocus,只有源码中第一个被解析到的生效,其余静默忽略 - 不支持 JS 动态设置:
el.autofocus = true或el.setAttribute('autofocus', '')都无效 - 仅适用于初始可见、未
disabled、非hidden状态的原生表单控件:<input type="text">、<textarea></textarea>、<button></button>✅;<input type="hidden">、<div tabindex="0"> ❌ <h3>移动端和 SPA 场景必须用 <code>element.focus()补位iOS Safari 几乎总是静默忽略
autofocus,Android Chrome 也日趋严格——这是浏览器策略,防止非用户手势触发软键盘弹出。SPA 路由切换后新渲染的输入框同样不会自动聚焦。正确做法是等 DOM 真实挂载、元素可见、且未被用户主动操作后再调用
focus():- 原生 JS:监听
DOMContentLoaded,加防御判断:if (input && document.activeElement !== input) input.focus() - React:用
useEffect+ref,并包裹if (typeof window !== 'undefined')防 SSR 报错 - Vue:在
onMounted中调用ref.value?.focus(),确保v-if已为true - 模态框场景:监听模态框的
shown事件(如 Bootstrap),或用MutationObserver检测元素插入
聚焦前必须检查元素是否真实可见且可聚焦
即使 DOM 已挂载,
focus()也可能失败——比如元素父容器是display: none,或自身offsetParent === null,或被inert属性阻断。推荐校验逻辑:
- 用
input.offsetParent !== null判断是否渲染可见(排除display: none/visibility: hidden) - 检查
!input.disabled && !input.readOnly - 若元素在 transition 动画中,需等动画结束(如监听
transitionend)再聚焦 - 移动端更稳妥的做法:绑定一次
click或touchstart到 body,回调里立即input.focus()—— 这满足“用户手势触发”要求,软键盘才会弹出
表单重置后 autofocus 不会恢复,需手动干预
<button type="reset"></button>点击后,所有字段还原初始值,但autofocus不会重新触发,焦点默认回到document.body。解决方式是监听
reset事件,在回调中手动聚焦目标元素:- 提前缓存 input 引用,避免重复查询
- 事件回调内直接调用
input.focus()即可(此时 DOM 结构未变,元素仍可聚焦) - 注意:不要在
reset事件里再查一遍document.querySelector,可能因 DOM 变动导致取不到
autofocus就完事”,也不是“JS 一执行focus()就一定成功”——它依赖可见性、可聚焦性、用户交互上下文三者同时满足。尤其在移动端,没有用户手势,focus()可能只让光标闪烁,却不弹键盘。 - 原生 JS:监听











