如何动态设置导航抽屉的tabindex,避免关闭时被Tab键聚焦?
解决导航抽屉关闭时内部元素可被Tab选中的问题
最优方案:使用inert属性
直接给导航抽屉的容器(比如你的<nav>元素)绑定inert属性,当抽屉关闭(showDrawer为false)时启用该属性:
<nav :inert="!showDrawer"> <!-- 抽屉内部的router-link、button等元素 --> </nav>
inert是原生HTML属性,作用是让元素及其所有子元素无法获得焦点,同时也会被屏幕阅读器忽略,完全符合需求,无需逐个修改内部元素,代码简洁且性能友好。现代浏览器(Chrome 84+、Firefox 101+、Safari 15.4+)都已支持该属性。
兼容方案:自定义Vue指令批量处理焦点
如果需要兼容旧浏览器,可以写一个自定义指令,自动处理容器内所有可聚焦元素的tabindex状态:
- 注册全局指令:
app.directive('focus-lock', { mounted(el, binding) { // 收集容器内所有可聚焦元素 const focusableElements = el.querySelectorAll( 'a[href], button, input, select, textarea, [tabindex]:not([tabindex="-1"])' ) el._focusableElements = Array.from(focusableElements) // 保存元素原本的tabindex值 el._originalTabIndexes = el._focusableElements.map(el => el.getAttribute('tabindex') || null) // 初始化状态 this.update(el, binding) }, updated(el, binding) { this.update(el, binding) }, update(el, binding) { const isLocked = binding.value el._focusableElements.forEach((el, index) => { if (isLocked) { el.setAttribute('tabindex', '-1') } else { // 恢复原本的tabindex,没有则移除属性(保持默认行为) const originalIndex = el._originalTabIndexes[index] if (originalIndex === null) { el.removeAttribute('tabindex') } else { el.setAttribute('tabindex', originalIndex) } } }) }, unmounted(el) { // 清理缓存 delete el._focusableElements delete el._originalTabIndexes } })
- 在组件中使用:
<nav v-focus-lock="!showDrawer"> <!-- 抽屉内部元素 --> </nav>
这个指令会自动识别容器内所有可聚焦元素,在抽屉关闭时设置tabindex="-1",打开时恢复原有状态,避免了逐个元素修改的繁琐。
补充说明
- 直接给父容器设置
tabindex="-1"无效的原因是:该属性只作用于容器本身,不会影响其子元素的焦点行为。 - 避免使用
display: none或移除DOM的方式,虽然能解决焦点问题,但会触发DOM重排/重绘,影响性能,你选择通过tabindex控制的思路是正确的。
内容的提问来源于stack exchange,提问作者Michael
相关产品推荐
相关产品推荐

