用 document.activeElement 和 element.matches(':focus') 判断焦点状态,注意 iframe/shadow DOM 限制、元素必须在文档中且可聚焦,tabindex 需配合可见性,:focus-visible 不可替代 :focus,focus() 需用户手势或确保元素就绪。
怎么判断一个元素当前有没有获得焦点
用 :focus 伪类是最直接的方式,但它只在样式层生效,不能用于 javascript 判断。真要检测焦点状态,得靠 document.activeelement 和 element.matches(':focus') 配合——前者返回当前聚焦的 dom 元素,后者能实时验证某个元素是否匹配 :focus(注意:仅对可聚焦元素可靠,比如 input、button、带 tabindex 的 div)。
常见错误现象:document.activeElement === element 在 iframe 内部或 shadow DOM 中可能失效;element.matches(':focus') 在元素未插入文档时总返回 false。
- 使用场景:表单校验后自动跳转到首个错误项并聚焦,需确认聚焦是否真正生效
- 兼容性影响:IE 不支持
matches(),需用msMatchesSelector()回退 - 性能提示:频繁轮询
activeElement不推荐,优先用focus/blur事件监听
为什么给 div 加了 tabindex 却 still 无法触发 :focus 样式
根本原因是:默认情况下 div 不是可聚焦元素,:focus 伪类对其不生效,哪怕加了 tabindex="0",也必须确保它已渲染在页面中、且没有被 display: none 或 visibility: hidden 隐藏。
容易踩的坑:tabindex="-1" 允许脚本聚焦(element.focus()),但用户无法用 Tab 键到达;tabindex="0" 可 tab 进入,但若父容器有 overflow: hidden 且元素溢出可视区,聚焦后浏览器未必滚动显示它。
- 检查点:用开发者工具选中该
div,看 computed 样式里:focus规则是否被应用(没生效就说明没真正聚焦) - 参数差异:
tabindex值为正数会改变 Tab 键顺序,一般只用0或-1 - 调试技巧:临时加一句
console.log(document.activeElement)在focus事件里,确认是不是被其他元素抢了焦点
:focus-visible 是不是可以完全替代 :focus
不能。:focus-visible 只在“由键盘操作触发焦点”时生效(比如按 Tab),鼠标点击或 element.focus() 调用不会激活它。它的设计初衷是避免鼠标用户看到突兀的焦点轮廓,而不是取代 :focus。
典型误用:用 :focus-visible 做所有焦点反馈,结果鼠标点开下拉菜单后,键盘用户按 Tab 却看不到任何焦点指示——因为此时 :focus 生效了,但 :focus-visible 没生效,而你又把 :focus 样式清空了。
- 正确姿势:用
:focus提供基础焦点样式,再用:focus-visible做增强(比如加动画、改颜色) - 兼容性注意:Safari 直到 15.4 才支持
:focus-visible,旧版需用js-focus-visiblepolyfill - 不要依赖它做逻辑判断:CSS 伪类无法被 JS 读取,也不能用于条件渲染
focus() 方法调用后为什么没反应
最常见原因是元素不可聚焦或尚未挂载。调用 element.focus() 前,必须确保该元素满足三个条件:在 DOM 中、display 不为 none、且是可聚焦元素(或已设 tabindex)。
另一个隐蔽问题:Chrome 65+ 对非用户手势触发的 focus() 会静默失败(比如在 setTimeout 或 API 回调里直接调),报错信息是 Failed to execute 'focus' on 'HTMLElement': Cannot set focus on a non-focusable element 或干脆无提示。
- 解决方案:包裹在
setTimeout(..., 0)里有时能绕过时机问题,但更稳妥的是监听DOMContentLoaded或用MutationObserver等待元素出现 - 移动端特别注意:iOS Safari 要求
focus()必须在用户手势(如click、touchend)同步回调中执行,异步延迟哪怕 1ms 都会失败 - 调试建议:在调用前加
console.assert(element.offsetParent !== null, 'element not visible')和console.assert(element.tabIndex >= 0 || element.hasAttribute('contenteditable'), 'not focusable')
事情说清了就结束
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











