如何禁用模态框弹出后的背景点击并修复记忆游戏计时器异常
解决记忆游戏的两个问题:计时器意外重启与背景点击禁用
先给你理清楚问题根源:计时器重启是因为牌组的点击事件没做状态判断,哪怕游戏结束了还能触发计时逻辑;而背景点击能生效,是因为模态框弹出后没做交互隔离。咱们分两步解决:
1. 模态框弹出后禁止背景点击(两种实用方案)
方案A:添加全屏遮罩层(推荐)
给模态框加一个覆盖整个屏幕的遮罩层,点击背景时实际触发的是遮罩,不会碰到底下的牌组:
<!-- 模态框结构 --> <div class="modal-overlay"></div> <div class="modal"> <!-- 你的模态框内容:总时长、星级展示 --> </div>
搭配CSS样式:
.modal-overlay { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0,0,0,0.3); /* 半透明黑,也可以设为全透明 */ z-index: 999; /* 层级要比牌组高,比模态框低 */ display: none; /* 默认隐藏 */ } /* 游戏结束时,给父容器加这个类来显示遮罩和模态框 */ .game-finished .modal-overlay, .game-finished .modal { display: block; }
当游戏结束弹出模态框时,给body或者游戏容器加上game-finished类,遮罩就会挡住整个背景,彻底禁止点击。
方案B:用CSS直接禁用牌组交互
如果不想加额外DOM元素,也可以在游戏结束时给牌组容器加pointer-events: none,直接让它失去点击响应:
.game-finished .card-container { pointer-events: none; }
这样模态框弹出后,牌组区域完全不会接收任何点击事件,从根源避免误触发。
2. 修复计时器意外重启的问题
光靠遮罩还不够,最好在计时逻辑里加一层状态判断,双重保险:
首先给游戏加个全局状态变量,比如isGameRunning,初始值为false:
let isGameRunning = false; let timerInterval; // 存储计时器ID,方便后续清除
然后在牌的点击事件里,先判断游戏状态:
document.querySelectorAll('.card').forEach(card => { card.addEventListener('click', () => { // 如果游戏已经结束,直接跳出,不执行任何逻辑 if (!isGameRunning) return; // 原来的牌翻转、匹配逻辑... // 只有当游戏未启动,且点击的是背面朝上的牌时,才启动计时器 if (!isGameRunning && card.classList.contains('back-face')) { isGameRunning = true; startTimer(); } }); });
最后在游戏结束的函数里,更新状态并停止计时器:
function finishGame() { // 停止计时器 clearInterval(timerInterval); // 重置计时器显示为0 document.getElementById('timer').textContent = '00:00'; // 标记游戏已结束 isGameRunning = false; // 弹出模态框并添加禁用背景的类 document.body.classList.add('game-finished'); }
这样一来,哪怕遮罩出点小问题,只要isGameRunning是false,点击牌组也不会触发任何逻辑,更不会重启计时器。
内容的提问来源于stack exchange,提问作者Caysle
相关产品推荐
相关产品推荐

