teleport 传送后的系统设置弹窗需实现闭环焦点控制:1. 弹窗容器设 role="dialog" 和 aria-modal="true",首次打开时聚焦首个可聚焦元素;2. 监听 tab 键实现焦点循环,过滤 disabled 和 tabindex="-1" 元素;3. v-if 放在 teleport 内部,配合 onmounted + nexttick 确保 dom 渲染后聚焦;4. 避免 overflow: hidden、outline: none 和 pointer-events: none 干扰焦点。

确保焦点锁定在 Teleport 传送后的系统设置弹窗内部,关键不是单纯“加个 Teleport 标签”,而是结合 DOM 结构、可访问性规范(ARIA)和原生浏览器行为做闭环控制。焦点不会自动被“锁住”,必须主动干预。
1. 弹窗容器需具备语义化与焦点捕获能力
Teleport 只负责移动 DOM,不提供焦点管理。必须手动让弹窗成为焦点陷阱(Focus Trap):
- 弹窗根元素添加 role="dialog" 和 aria-modal="true",告知屏幕阅读器这是模态上下文,外部内容应不可交互
- 首次打开时,用
el.focus()主动聚焦到弹窗内第一个可聚焦元素(如标题、首个输入框或关闭按钮),避免焦点停留在触发按钮上 - 确保弹窗内至少有一个
tabindex="0"或原生可聚焦元素(<button></button>、<input>等),否则 tab 键可能直接跳出弹窗
2. 实现焦点循环与拦截外部跳转
仅聚焦一次不够,用户按 Tab/Shift+Tab 时必须限制在弹窗内循环:
递归分析 Vue 项目组件依赖,从入口文件生成组件层级图,支持 Vue 2/3,输出组件名、文件路径和属性。适用于分析组件结构、排查依赖或了解项目架构。
- 监听弹窗容器的
keydown事件,捕获Tab键;获取所有可聚焦子元素(querySelectorAll('button, [href], input, select, textarea, [tabindex]')) - 当焦点即将移出最后一个元素时,阻止默认行为,并将焦点设回第一个可聚焦项;反之亦然
- 注意:不要依赖第三方库(如 focus-trap)时,务必过滤掉
disabled元素和tabindex="-1"元素,避免误判
3. 配合 Teleport 的挂载时机与状态同步
焦点逻辑必须与 Teleport 渲染节奏一致,否则可能操作到不存在的节点:
-
v-if 必须放在 Teleport 内部最外层容器上,确保 DOM 真实挂载后再执行焦点逻辑(若写在外层,Teleport 内容尚未插入 body,
querySelector会返回 null) - 使用
onMounted+nextTick(或setTimeout(..., 0))确保 DOM 已渲染完成再聚焦,尤其当弹窗含异步加载内容时 - 关闭弹窗时,恢复焦点到触发按钮(保存其 ref),提升可访问性体验
4. 避免样式干扰导致焦点失效
某些 CSS 会间接破坏焦点可见性或可到达性:
- 禁用弹窗父级(如
#teleport-modal-root)的overflow: hidden或transform,否则可能使focus-visible样式异常或键盘导航失灵 - 确保弹窗内所有交互元素有明确的
:focus-visible样式,且不被outline: none全局覆盖 - 慎用
pointer-events: none在遮罩层上——它虽能防点击穿透,但也会阻断键盘焦点进入弹窗(应改用aria-hidden="true"隐藏背景内容)
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!









