autofocus在异步渲染中无效,仅在html初始解析时生效;手动focus需满足已挂载、可见、可聚焦三条件,并避开ssr环境与ios限制。

autofocus在异步组件里根本不会触发
它只在 HTML 初始解析阶段扫描一次,Vue 的 v-if、React 的 useState 切换、fetch().then(html => el.innerHTML = ...) 插入的元素,哪怕 DOM 里真有 autofocus 属性,浏览器也完全无视——不是没写对,是压根不看。
常见现象:<input autofocus> 写在 Vue <template></template> 里,但组件挂载后光标不动;Modal 弹出后用 innerHTML 注入表单,输入框始终没焦点;服务端返回带 autofocus 的片段,插入后焦点却落在旧页面顶部的输入框上(因为它是“第一个被解析到”的)。
手动 focus() 必须满足三个条件才可靠
不能一上来就 input.focus(),得等元素真正可交互:已挂载、可见、未被禁用。否则要么报错,要么静默失败。
- 检查是否挂载:
input.offsetParent !== null或用框架 ref(如 Vue 的inputRef.value、React 的ref.current) - 检查是否可见:
getComputedStyle(input).display !== 'none' && getComputedStyle(input).visibility !== 'hidden' - 检查是否可聚焦:
input.disabled === false && input.tabIndex !== -1 - 避免覆盖用户操作:
if (document.activeElement !== input) { input.focus(); }
移动端和 Safari 要绕开 autofocus 的静默丢弃
iOS Safari 对非用户手势触发的聚焦极其严格,autofocus 几乎总被忽略,且不报错、不提示。软键盘也不会弹出——这不是 bug,是平台策略。
安全做法是绑定在用户明确动作之后:
- 点击按钮打开 Modal 后,立刻调用
input.focus() - 路由跳转后,等
useEffect(() => { ref.current?.focus() }, [])(React)或onMounted(() => inputRef.value?.focus())(Vue) - 需要强制唤起键盘时,加
{ preventScroll: true }:input.focus({ preventScroll: true }),autofocus不支持这个参数
SSR 和 hydration 场景下 focus() 容易报错
服务端渲染时 document 不存在,直接调用 input.focus() 会抛 ReferenceError: document is not defined。
必须包裹运行环境判断:
- 通用判断:
if (typeof window !== 'undefined') { input.focus(); } - React 中推荐在
useEffect里调用(它只在客户端执行) - Vue 中用
onMounted钩子,而非created - 不要用
setTimeout(() => focus(), 0)硬等——可能和原生autofocus冲突,造成两次聚焦抖动
真正容易被忽略的是:焦点状态不等于可编辑状态。即使 input.focus() 成功,iOS 上仍可能不弹键盘;而 autofocus 即使生效,也不会触发 focus 事件——监听它捕获不到任何东西。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











