如何让记忆配对卡牌游戏的点击事件监听器仅触发一次?
解决方法
你只需要加几个简单的校验逻辑就可以解决重复点击的问题,不需要频繁绑定/解绑事件监听器,修改后的JS代码如下:
const cards = document.querySelectorAll(".card"); const images = document.querySelectorAll("img"); let scoreElement = document.getElementById("score"); let failsElement = document.getElementById("fails"); let failsAmount = 0; let scoreAmount = 0; let pickedCards = []; // 新增校验锁,匹配过程中禁止点击 let isChecking = false; function pickCards() { for (let i = 0; i < cards.length; i++) { cards[i].addEventListener("click", function() { // 加两个校验:正在匹配中、当前卡已经被翻转,都直接终止逻辑 if (isChecking || cards[i].classList.contains("flipcard")) return; cards[i].classList.add("flipcard"); pickedCards.push(images[i]); // 只有选够2张卡才执行匹配校验 if (pickedCards.length === 2) { checkForMatch(); } }); } } function checkForMatch() { // 匹配过程锁死点击 isChecking = true; if (pickedCards[0].src == pickedCards[1].src) { alert("Match! +1 score"); scoreAmount++; scoreElement.textContent = "Score: " + scoreAmount; pickedCards = []; // 匹配成功直接释放锁 isChecking = false; } else { hideCards(); alert("Not a match! Sorry!"); failsAmount++; failsElement.textContent = "Fails: " + failsAmount; pickedCards = []; } } function hideCards() { setTimeout(function() { for (let i = 0; i < cards.length; i++) { cards[i].classList.remove("flipcard"); } // 等翻转动画执行完再释放锁 isChecking = false; }, 1000); } pickCards();
修改说明
- 新增
isChecking全局锁变量,当两张卡正在匹配、或者不匹配正在翻回背面的过程中,禁止用户点击任何卡牌,避免逻辑混乱 - 点击卡牌时先判断当前卡牌是否已经有
flipcard类,如果已经翻转就不响应点击,解决同一张卡反复点击翻转的问题 - 调整匹配逻辑的触发时机,只有选够2张卡才执行匹配校验,避免选第一张卡时读取
pickedCards[1]出现undefined报错 - 翻回卡牌的逻辑统一放在setTimeout回调里,保证翻转动画执行完再释放锁,用户才可以继续操作
内容的提问来源于stack exchange,提问作者Mitrixsen
相关产品推荐
相关产品推荐

