autofocus仅在html初始解析时生效,是浏览器对源码的一次性扫描行为;之后任何dom变更、组件挂载或css显隐切换均无效,需用js手动focus()并确保在用户手势内调用。

autofocus 属性写上去不生效?不是你代码错了,是它根本没机会运行——浏览器只在 HTML 初始解析时扫一眼这个属性,之后任何 DOM 变更、组件挂载、CSS 显隐切换,它都完全无感。
autofocus 只在页面首次加载时起一次作用
它不是 JS 可控的开关,而是浏览器对原始 HTML 源码的一次性扫描行为。这意味着:
-
document.body.innerHTML = '<input autofocus>'→ 属性存在,但不会触发聚焦 -
input.autofocus = true或input.setAttribute('autofocus', '')→ 完全无效 - Vue/React 组件里写
<input autofocus>→ hydration 后 DOM 已存在,错过解析时机 - 服务端返回新表单并用 JS 插入 → 浏览器不会重新解析 HTML,autofocus 静默忽略
哪些元素和状态真正支持 autofocus
必须同时满足:可聚焦 + 可输入 + 未禁用 + 初始可见。常见组合如下:
- ✅ 稳定支持:
<input type="text">、<input type="search">、<input type="email">、<textarea></textarea> - ⚠️ 有条件支持:
<button></button>(Chrome/Firefox 行为一致,Safari 偶尔跳过)、<select></select>(Firefox 和旧 Safari 明确不支持,错误信息:autofocus is not supported on <select></select>) - ❌ 完全无效:
<input type="hidden">、<input type="checkbox">、<input disabled>、<div autofocus>、<code><input style="display:none"> - 隐藏即失效:父容器含
display: none、visibility: hidden、inert,或自身tabindex="-1"→ autofocus 被跳过 - 原生 JS:
DOMContentLoaded后检查document.activeElement !== input,避免覆盖用户当前焦点 - React:
useEffect(() => { inputRef.current?.focus() }, []),加if (typeof window !== 'undefined')防 SSR 报错 - Vue 3:
onMounted(() => inputRef.value?.focus()),确保v-if已为true - 模态框场景:监听
shown事件(如 Bootstrap)或transitionend后再聚焦,而非依赖 CSS 切换 -
autofocus不会触发focus事件(聚焦发生在事件循环之前),而.focus()会 -
.focus({ preventScroll: true })可避免页面意外滚动,autofocus没这个能力 -
.focus()在元素不可见或被遮挡时可能静默失败,需手动校验offsetParent !== null和!input.disabled - 多个
autofocus元素只处理第一个(按源码顺序),其余被忽略;而 JS 可精准指定目标,不受 DOM 顺序限制
移动端和 SPA 场景下必须用 JS 手动 focus()
iOS Safari 几乎总是静默忽略 autofocus,目的是防止非用户手势触发软键盘弹出遮挡内容;SPA 路由切换后新渲染的输入框也不会自动聚焦。可靠做法是等 DOM 真实挂载、元素可见、且未被用户主动操作后再调用 .focus():
autofocus 和 .focus() 的关键区别在哪
autofocus 是声明式、一次性、无反馈的;.focus() 是命令式、可重试、可加判断、可传选项的控制方式:
真正容易被忽略的是:即使 .focus() 成功执行,在 iOS Safari 中若不在用户手势(click、touchstart)回调内调用,软键盘仍大概率不弹。这不是 bug,是平台策略——得把聚焦逻辑“包裹进用户动作里”,比如按钮点击后立即聚焦,而不是页面一出来就硬上。











