focus事件未触发主因是元素不可聚焦:div/span需加tabindex="0",disabled、隐藏或DOM未就绪均导致静默;须用addEventListener绑定,且focus/blur不冒泡,应改用focusin/focusout实现委托。

focus 事件不是“写了就能监听到”的,它对元素状态、绑定方式、触发时机都有硬性要求。直接用 onfocus 属性或在错误时机调用 focus(),大概率收不到事件。
为什么 focus 事件没触发?
最常见原因不是代码写错,而是元素根本不满足可聚焦前提:
-
div、span默认不可聚焦,必须加tabindex="0"(tabindex="-1"不行) -
input被设为disabled或display: none/visibility: hidden→ 事件彻底静默 -
contenteditable="true"的元素可以触发,但需注意 Safari 对它的focus行为有延迟 - 用
innerHTML或框架(Vue/React)动态插入的元素,autofocus属性无效,且若 DOM 尚未完成渲染就绑事件,addEventListener会绑到null
用 addEventListener 绑定 focus 和 blur
别用 onfocus="handler()" 内联写法——它覆盖已有逻辑、无法解绑、不支持传参,还容易在组件卸载后泄漏。
正确写法:
const input = document.getElementById('email');
input.addEventListener('focus', () => {
input.classList.add('focused');
});
input.addEventListener('blur', () => {
if (!input.value.trim()) {
input.classList.add('error');
}
});
注意:focus 和 blur 不冒泡,所以不能在父容器上监听子元素的聚焦。如果要统一处理整个表单的输入框,改用 focusin / focusout(它们冒泡,IE9+ 全支持)。
立即学习“前端免费学习笔记(深入)”;
移动端和 SPA 场景下怎么确保能聚焦?
iOS Safari 和多数 WebView 对自动聚焦极其严格:非用户手势上下文(如 fetch 回调、定时器、路由切换后)调用 input.focus(),光标可能亮、但软键盘不弹出。
可靠做法是校验并兜底:
- 确保聚焦发生在
click、touchstart等用户手势的同步回调内 - 异步场景(如模态框打开后)用
requestAnimationFrame延迟一次绘制再聚焦,比setTimeout(..., 0)更稳 - iOS 15+ 可临时加
readonly再移除:input.setAttribute('readonly', 'readonly'); input.focus(); input.removeAttribute('readonly'); - 聚焦前检查是否已可见:
input.offsetParent !== null,必要时配input.scrollIntoView({ block: 'nearest' })
表单重置后焦点丢了怎么办?
form.reset() 会清空值,同时强制当前聚焦元素失焦——这是标准行为,但常被忽略。
监听 reset 事件手动恢复即可:
const form = document.getElementById('userForm');
const nameInput = document.getElementById('name');
form.addEventListener('reset', () => {
setTimeout(() => nameInput.focus(), 0);
});
注意:不要在 reset 回调里立刻 focus(),某些浏览器会因重置过程未完全结束而失败,加 setTimeout 是最小成本的兼容方案。
focus 就成哑巴。



















