快速点击卡片导致记忆游戏异常的问题修复求助
快速点击卡片导致记忆游戏异常的问题修复求助
我做了一个记忆配对小游戏,正常慢慢点击卡片的时候,游戏逻辑都能正常运行——翻开第一张,再翻第二张,匹配就保留翻开状态,不匹配就过一会儿合上。但如果我快速狂点卡片,就会出现奇怪的bug:有些明明没配对的卡片会被判定为匹配,一直保持翻开状态,完全打乱游戏节奏。
先贴一下我目前的游戏代码:
HTML 代码
<!DOCTYPE html> <html> <body style="justify-self:center;"> <h1 style="justify-self:center">Memory Game</h1> <div id="cont" style="width:px"> <p class="stats" style="justify-self:center ;"></p> <div class='cardContainer' style="justify-self:center ;"> <div class='card' id="1"></div> <div class='card' id="1"></div> <div class='card' id="2"></div> <div class='card' id="2"></div> <div class='card' id="3"></div> <div class='card' id="3"></div> <div class='card' id="4"></div> <div class='card' id="4"></div> <div class='card' id="5"></div> <div class='card' id="5"></div> <div class='card' id="6"></div> <div class='card' id="6"></div> <div class='card' id="7"></div> <div class='card' id="7"></div> <div class='card' id="8"></div> <div class='card' id="8"></div> </div> <div style="justify-self:center ;"><button id="reset" style="margin-top: 20px; ">Reset Game</button></div> <script src="mg.js"></script> </div> </body> </html>
JavaScript 代码
const cards = document.querySelectorAll('.card') let clickCount = 0 let id = [] let matched = 0 function shuffle() { cards.forEach(card => { let pos = Math.floor(Math.random() * 12); card.style.order = pos }) } shuffle() function checkMatch() { if (id[0] == id[1]) { return true } else { return false } } cards.forEach(card => { card.addEventListener('click', () => { card.innerHTML = card.id id.push(card.id) card.setAttribute('open', 'true') clickCount += 1 console.log(clickCount) if (clickCount == 2) { let result = checkMatch() clickCount = 0 if (result == false) { id = [] setTimeout(() => { document.querySelectorAll('[open="true"]').forEach((card) => { card.innerHTML = ''; card.removeAttribute('open', 'true') }) }, 100) } else { console.log('matched') id = [] document.querySelectorAll('[open="true"]').forEach((card) => { card.removeAttribute('open', 'true'); card.replaceWith(card.cloneNode(true)) }) matched += 2 } } if (matched == 16) { console.log('You win') } }) })
问题原因分析
这个bug的核心是快速点击会绕过我们的点击计数逻辑,异步操作的状态没有被正确锁定:
- 当点击第一张卡片后
clickCount=1,快速点击多张卡片会让clickCount直接跳到2、3、4... 此时id数组会塞入多个卡片ID,标记为open="true"的卡片也不止两张,后续匹配逻辑直接混乱 setTimeout是异步操作,在它等待执行的100ms里,用户的快速点击会继续触发事件,导致状态没有被及时重置,最终出现错误的卡片保留
修复后的完整代码
我调整了逻辑,主要加了状态锁定和点击有效性判断,完美解决了快速点击的问题:
const cards = document.querySelectorAll('.card') let clickCount = 0 let id = [] let matched = 0 // 新增:标记是否正在处理卡片匹配,防止快速点击干扰 let isProcessing = false function shuffle() { cards.forEach(card => { let pos = Math.floor(Math.random() * 12); card.style.order = pos }) } shuffle() function checkMatch() { return id[0] === id[1] } // 封装点击事件绑定,方便克隆卡片后重新绑定 function bindCardClick(card) { card.addEventListener('click', () => { // 新增判断:正在处理中、卡片已翻开、无ID(已匹配)的情况直接返回 if (isProcessing || card.hasAttribute('open') || !card.id) { return } card.innerHTML = card.id id.push(card.id) card.setAttribute('open', 'true') clickCount += 1 if (clickCount === 2) { // 锁定状态,禁止新点击 isProcessing = true const result = checkMatch() clickCount = 0 if (!result) { id = [] setTimeout(() => { document.querySelectorAll('[open="true"]').forEach((card) => { card.innerHTML = ''; card.removeAttribute('open', 'true') }) // 处理完成解锁 isProcessing = false }, 500) // 把时间调长,用户有足够时间看卡片,体验更好 } else { console.log('matched') id = [] document.querySelectorAll('[open="true"]').forEach((card) => { card.removeAttribute('open', 'true'); // 克隆卡片并重新绑定事件 const newCard = card.cloneNode(true) bindCardClick(newCard) card.replaceWith(newCard) }) matched += 2 // 处理完成解锁 isProcessing = false } } if (matched === 16) { console.log('You win! 🎉') // 这里可以加游戏胜利的弹窗或提示 } }) } // 初始绑定所有卡片点击事件 cards.forEach(card => bindCardClick(card)) // 新增重置按钮逻辑 document.getElementById('reset').addEventListener('click', () => { matched = 0 clickCount = 0 id = [] isProcessing = false // 重置所有卡片状态 document.querySelectorAll('.card').forEach(card => { card.innerHTML = '' card.removeAttribute('open') }) // 重新洗牌 shuffle() })
修复关键要点
- 状态锁
isProcessing:处理两张卡片匹配逻辑时,禁止新的点击触发,确保每次只处理一组卡片 - 点击有效性判断:过滤掉正在处理、已翻开、已匹配的卡片点击,避免无效操作
- 优化克隆卡片事件:用函数封装点击绑定,确保克隆后的卡片能正常响应点击
- 延长延迟时间:把100ms改成500ms,用户体验更友好,也减少快速点击的概率
- 补全重置功能:给重置按钮绑定了逻辑,用户可以随时重启游戏
现在再快速点击卡片,游戏逻辑会保持稳定,不会再出现错误匹配的情况啦~
备注:内容来源于stack exchange,提问作者thiyaharajan rajkumar
相关产品推荐
相关产品推荐

