autofocus在页面跳转后必然失效,是浏览器规范行为而非bug;SPA中需手动调用focus()并确保元素已渲染、可见且未禁用,iOS Safari还要求必须绑定用户手势触发。

autofocus在页面跳转后必然失效,这不是 bug 是规范行为
浏览器只在初始 HTML 解析时扫描 autofocus,后续所有路由跳转(包括 Vue Router、React Router、原生 history.pushState)都不会重新触发它。你看到“新页面没聚焦”,不是代码写错了,是浏览器根本没打算看第二眼。
SPA 路由切换后 focus() 必须手动调用,且时机要卡准
不能等组件挂载完就立刻 focus(),得确保元素已渲染、可见、未被禁用。常见错误是:DOM 节点存在但还在 CSS 动画中,或父容器带 display: none、inert、visibility: hidden。
- React 中用
useEffect(() => { inputRef.current?.focus(); }, []),但必须配合ref正确绑定到实际 DOM 节点 - Vue 中推荐
onMounted(() => nextTick(() => inputRef.value?.focus())),避免v-if条件未满足导致inputRef.value为null - 原生 JS 可监听
popstate或hashchange,再用requestAnimationFrame(() => input.focus())延迟一帧,避开样式计算未完成的窗口期
iOS Safari 下 focus() 必须绑定用户手势,否则静默失败
这是最容易被忽略的硬性限制:iOS Safari 要求 focus() 必须发生在 click、touchend、keydown 等用户手势同步上下文中。单纯靠路由跳转后的生命周期钩子,99% 失效。
- 模态框/搜索页等场景,把聚焦逻辑直接写进按钮点击事件里:
button.addEventListener('click', () => input.focus()) - 登录页这类必须自动触发的场景,可加一层
setTimeout(() => input.focus(), 300),虽不 100% 可靠,但比无延迟调用成功率高 - 永远加上防护判断:
if (input && document.activeElement !== input) input.focus(),避免打断用户正在操作的其他输入框
多弹窗或异步加载时,autofocus 属性完全不可信
哪怕你写了十个 <dialog><input autofocus></dialog>,浏览器也只对第一个解析到的生效;异步 fetch 后插入的 HTML 片段,里面的 autofocus 属性纯属摆设。
立即学习“前端免费学习笔记(深入)”;
- 动态插入内容后,必须显式调用
input.focus(),且要等 DOM 更新完成(如 Vue 的nextTick、React 的useLayoutEffect) - 多个弹窗快速切换时,优先监听
dialog的focusin事件,再聚焦目标输入框,比盲目setTimeout更可靠 - 服务端渲染(SSR)后 hydration 的
<input autofocus>不会聚焦——因为 DOM 已存在,autofocus 的执行窗口早已关闭
真正麻烦的从来不是“怎么写”,而是“什么时候调、在什么条件下调、要不要调”。iOS 手势限制、SPA 路由不刷新 DOM、异步加载时机错位——这些叠加起来,让纯 HTML 方案在真实项目里基本形同虚设。



















