focus() 失败主因是元素不可聚焦,需确保其为表单控件、带 tabindex="0" 的元素或原生可聚焦元素;动态插入时用 requestanimationframe 延迟聚焦;焦点委托应使用冒泡的 focusin/focusout;autofocus 需谨慎避免破坏可访问性。

focus() 方法调用后没反应?检查元素是否可聚焦
直接调用 element.focus() 失败,最常见的原因是目标元素默认不可聚焦。只有表单控件(如 <input>、<button></button>)、带 tabindex 的元素,或原生可聚焦语义元素(如 <a href></a>)才能获得焦点。
实操建议:
- 对非表单容器(如
<div>、<code><span></span>)手动添加tabindex="0",使其参与顺序流且可被.focus()激活 - 避免用
tabindex="-1"后再调用.focus()—— 它只支持程序聚焦,不参与 Tab 导航,但能用;若需两者兼顾,用tabindex="0" - 检查元素是否被
display: none或visibility: hidden隐藏:前者完全不可聚焦,后者虽不可见但仍可聚焦(可能引发 UX 问题) - 用
requestAnimationFrame()延迟一次绘制周期:element.insertAdjacentHTML('beforeend', '<input type="text">');<br>const input = element.querySelector('input');<br>requestAnimationFrame(() => input.focus()); - 对 Shadow DOM 内元素,需先确认
shadowRoot已挂载,再查子节点并聚焦 - 避免在
setTimeout(..., 0)中聚焦 —— 它不保证 DOM 渲染完成,比requestAnimationFrame更不可靠 - 在表单容器上监听
focusin,统一处理所有子控件聚焦逻辑:form.addEventListener('focusin', (e) => {<br> if (e.target.matches('input, select, textarea')) {<br> e.target.classList.add('focused');<br> }<br>}); - 注意:IE 11 及更早版本中
focusin/focusout是专有事件,现代浏览器已标准化,无需 polyfill - 不要用
focusin替代.focus()—— 它只是监听手段,不能触发聚焦 - 仅对首个有意义的交互控件(如登录页的
email输入框)谨慎使用autofocus,且必须配合data-focusable等标记供辅助技术识别 - 模态框打开后,应主动将焦点移到第一个可聚焦子元素,并用
inert或aria-hidden="true"隐藏背景内容的可聚焦性 - 检测用户是否启用了“减少动画”或“无障碍导航”偏好(通过
window.matchMedia('(prefers-reduced-motion: reduce)')或document.hasFocus()上下文判断),动态决定是否聚焦
如何确保动态插入的元素能正确获取焦点?
DOM 节点插入后立即调用 .focus() 很可能失败,尤其在使用 React、Vue 或原生 innerHTML 插入时 —— 浏览器尚未完成渲染或焦点管理尚未就绪。
实操建议:
focusin 和 focusout 事件比 focus/blur 更适合做焦点代理吗?
是的。focus 和 blur 不冒泡,无法在父容器监听子元素聚焦行为;而 focusin 和 focusout 支持事件冒泡,是实现焦点委托(focus delegation)的唯一可靠方式。
实操建议:
自动聚焦影响可访问性?绕过 autofocus 的陷阱
autofocus 属性看似方便,但在多页面应用或模态框中极易破坏屏幕阅读器流程、打断用户操作,甚至导致键盘焦点“丢失”在不可见区域。
实操建议:
.focus(),而是判断「此刻该不该聚焦」「聚焦后焦点去哪」「聚焦后其他地方还该不该能聚焦」——这些都得结合语义结构、用户输入设备和辅助技术上下文来定。











