引导层需阻断点击穿透、动态等待DOM挂载、兼容触控事件、接管键盘焦点。遮罩设pointer-events:auto并精确控制高亮区;用MutationObserver或框架生命周期确保元素存在;绑定touchstart+click并防默认行为;管理tabindex与焦点流,保障可访问性。

引导层点击穿透导致新手点不到按钮
HTML引导层如果只是用 position: fixed 盖一层半透明遮罩,又没处理 pointer-events,用户实际点击会直接穿透到下层 DOM,教学提示还在,但按钮根本点不中。这不是“没反应”,是浏览器真把事件传下去了。
必须显式阻断事件冒泡并禁用穿透:
- 遮罩层加
pointer-events: none是错的——这会让它完全不可交互,连关闭按钮都点不了 - 正确做法:遮罩层设
pointer-events: auto,再用z-index确保它在最上层;所有可点击的教学区域(如高亮按钮)用pointer-events: auto单独开启,其余区域用pointer-events: none遮挡 - 关键细节:被高亮的按钮本身要加
pointer-events: auto,否则即使遮罩开了,按钮仍被遮罩层“压住”而无法响应
引导步骤跳转时 DOM 已销毁或未渲染
很多新手引导库依赖 document.querySelector 查找目标元素,但 React/Vue 组件可能还没挂载,或用户快速跳步时上一步的 DOM 已被卸载——结果报错 Cannot read property 'getBoundingClientRect' of null,引导直接卡死。
不能靠 try-catch 顶着走,得主动等:
立即学习“前端免费学习笔记(深入)”;
- 对动态渲染的元素,不用轮询
querySelector,改用MutationObserver监听父容器变化,检测到目标节点插入后再启动定位 - Vue 场景优先用
nextTick,React 推荐useEffect+ref回调,确保元素真实挂载后再计算位置 - 如果目标是异步加载的模块(比如权限控制后才显示的按钮),引导逻辑必须和该模块的加载状态耦合,不能假设“页面一打开所有按钮都在”
移动端 touchstart 不触发 click 导致下一步卡住
在 iOS Safari 或部分安卓 WebView 中,只监听 click 事件的引导按钮,在触摸屏上可能完全无响应——因为 click 有 300ms 延迟且受 focus/active 状态影响,而引导层常缺 cursor: pointer 或 user-select: none,进一步加剧兼容问题。
必须同时覆盖触控与鼠标路径:
- 按钮绑定
touchstart和click双事件,并在touchstart中立刻调用event.preventDefault()防止滚动干扰 - CSS 加上
-webkit-tap-highlight-color: transparent和user-select: none,避免点击反馈错乱 - 不要用
onclick="nextStep()"行内写法,移动端容易因解析时机问题丢失绑定
引导层挡住焦点管理,键盘用户无法操作
纯鼠标引导没问题,但当产品需支持无障碍(WCAG)或内部有键盘党用户时,引导层若没接管 tabindex 和 focus 流,键盘用户按 Tab 就会跳出引导、聚焦到页面底部按钮,教学完全失效。
焦点流不是锦上添花,是引导能跑完的前提:
- 遮罩层本身设
tabindex="-1"并在 show 时.focus(),防止焦点留在上一个输入框里 - 每步引导只允许当前高亮元素可聚焦(
tabindex="0"),其他可交互元素临时设tabindex="-1"或aria-hidden="true" - 按 Esc 关闭引导时,必须把焦点还给触发引导的原始按钮(存个
triggerEl引用),否则键盘用户会迷失
引导层不是 UI 装饰,它是临时接管用户注意力的控制层。DOM 存在性、事件路径、焦点顺序、触控响应——四个点漏一个,新手就卡在第一步。



















