一、问题现象
点击弹窗【关闭按钮】,弹窗无法关闭或关闭极慢
点击关闭的同时,底层角色会跑动、触发地面移动逻辑
视觉上层弹窗置顶,但移动端依然穿透底层游戏画布
二、根本原因(核心!99% 同类Bug都是这个问题)
不是层级(z-index)问题,是移动端事件穿透 + 冒泡穿透
Touch 事件不受 CSS 层级限制
PC 端 z-index 高就能挡住点击
移动端 touchstart / touchmove 会穿透置顶DOM,直接触发底层游戏场景的移动事件
关闭按钮点击事件冒泡
点击按钮 → 冒泡到 game-scene → 触发地面移动
移动逻辑执行、状态冲突,导致弹窗变量卡住、关不掉
三、最终三层根治方案(缺一不可)
1. DOM 层:彻底阻止事件冒泡(@click.stop)
弹窗盒子 + 关闭按钮 双重 stop,截断所有向下穿透:
<div v-if="showDialog" class="dialog-mask" @click.self="closeDialog"> <div class="dialog-box" @click.stop> <button @click.stop="closeDialog">关闭对话</button> </div> </div>作用:点击弹窗内部完全不会传递到游戏层。
2. JS 逻辑层:弹窗打开时直接禁用所有地面移动
在所有场景触摸函数最开头加拦截:
if(showDialog.value) return修改函数:
handleSceneTouchStart
handleSceneTouchMove
handleSceneTouchEnd
作用:弹窗打开期间,底层移动逻辑彻底失效,杜绝状态冲突。
3. CSS 层:全局阻断底层交互(终极保险)
.game-scene:has(.dialog-mask) { pointer-events: none; } .dialog-mask { pointer-events: auto; } .dialog-box { pointer-events: auto; }作用:弹窗存在时,整个游戏场景禁止任何点击、触摸穿透。
四、修复后完整正确逻辑流程
点击角色 → 打开弹窗 showDialog = true
弹窗打开瞬间:CSS 禁用底层游戏交互 + JS 拦截触摸移动
点击关闭按钮:@click.stop 只执行 closeDialog
弹窗关闭后,游戏交互自动恢复
完全不会触发人物移动、无状态冲突、弹窗秒关
五、常见误区总结(踩坑记录)
❌ 误区1:以为 z-index 不够高 → 层级不解决移动端touch穿透
❌ 误区2:只给盒子加 stop,不给按钮加 → 依然穿透
❌ 误区3:只改CSS不改JS → 依然有概率状态卡死
✅ 正确:CSS + JS + DOM事件 三层拦截才是根治
六、适用场景(可复用通用方案)
所有 Vue + 移动端游戏 / PIXI / Canvas / 触摸场景 的弹窗穿透问题,均可直接套用此三层方案解决。
弹窗关闭触发人物移动、弹窗关不掉问题 — 最终解决方案总结文档
王家视频教程图书馆2026-06-21 8:01