autofocus在spa路由切换后必然失效,因它仅在html解析时执行一次;后续js驱动的dom变更(如react/vue router导航)不会触发,此时autofocus仅为静态属性。

autofocus在SPA路由切换后必然失效,不是bug是规范
它只在浏览器解析原始HTML时执行一次,后续所有JS驱动的DOM变更(包括React Router跳转、Vue Router导航、组件挂载)都不会重新触发。你看到新页面输入框没聚焦,不是代码写错,是浏览器根本没看第二眼——autofocus属性此时只是个静态字符串,毫无行为意义。
为什么手动focus()也常失败?四个硬性前提缺一不可
element.focus()不是“调了就完事”,浏览器会静默拒绝,且不报错。必须同时满足:
- 元素已真实挂载到DOM(
ref.current不能为null) - 元素可见:
getComputedStyle(el).display !== 'none'且visibility !== 'hidden' - 未被
inert或disabled禁用 - 调用上下文需有用户手势(iOS Safari尤其严格:click/tap/keydown同步链路内才允许)
React/Vue中聚焦时机怎么选?别信useEffect/onMounted就万事大吉
框架生命周期钩子只是起点,不是终点。常见踩坑点:
开箱即用的技能链路由引擎。13 条预定义链覆盖搜索、开发、审查、MLOps、法律、创意等场景,三层路由架构(触发词→SAD反馈→DAG编排),recall@10=96.97%。配置驱动(chains.yaml),零代码扩展。pip install skill-weave-chains 一键安装。
- React:
useEffect(() => { inputRef.current?.focus(); }, [])若inputRef绑定的是条件渲染前的空节点,current就是null - Vue:
onMounted(() => inputRef.value?.focus())若配合v-if,需加nextTick或setTimeout(() => ..., 0)确保DOM真正更新 - 更稳妥方案:用
requestAnimationFrame(() => el.focus()),避开CSS transition未结束导致的visibility: hidden状态 - 必须加保护逻辑:
if (el && document.activeElement !== el) el.focus(),防止打断用户正在操作的其他输入框
iOS Safari下多层弹窗+路由跳转=聚焦大概率静默失败
这不是兼容性问题,是Apple主动限制:焦点必须发生在用户手势(点击按钮)的同步上下文中。如果弹窗由路由跳转间接触发(比如菜单项 → 状态变更 → 显示dialog),整个链路脱离原始手势,focus()就会白忙活。
真正能落地的做法只有两个:
- 把弹窗打开动作绑定在用户显式点击事件里(如
@click="openModal"),并在该回调内立即调用input.focus() - 若必须走路由触发,降级处理:不自动聚焦,改用
tabindex="-1"占位元素 +aria-live="polite"播报页面变更,把控制权交还给键盘用户
复杂点不在代码长短,而在时机判断和平台差异——iOS Safari的聚焦限制、多弹窗的DOM可见性、路由切换与组件挂载的微秒级时序差,任何一个没对齐,光标就停在原地不动。










