猜颜色游戏点击Play Again后无法触发获胜条件求助
猜颜色游戏Play Again后无法触发获胜条件问题排查
我是编程新手,听说这里是提问的最佳平台!以下是我的问题:
我开发了一款猜颜色JavaScript游戏,首次运行正常,选择正确颜色会显示"You Win 🎉";但点击Play Again按钮重置游戏后,无论选择正确选项都无法触发获胜条件。原本使用全局变量pickedColor时功能正常,为精简代码减少全局变量后出现该问题,恳请帮忙排查。
游戏代码如下:
'use strict' //DOM Elements declaration. const square = document.getElementById("color1") const guesses = document.getElementsByClassName("guess"); const guessArr = [...guesses] const playAgain = document.querySelector(".play-again"); const title = document.getElementById("title") var playing = true; init(); function init() { let pickedColor = createColor(); console.log(pickedColor); title.innerHTML = "GUESS THE COLOUR!" square.style.backgroundColor = pickedColor; playing = true; updateGuesses(pickedColor); guess(pickedColor); } //Setting the playing field. function createColor () { let r = Math.floor(Math.random() * 255); let g = Math.floor(Math.random() * 255); let b = Math.floor(Math.random() * 255); let color = `rgb(${r}, ${g}, ${b})` return color } function updateGuesses (pickedColor) { for (let i=0; i < 3; i++){ guesses[i].textContent = createColor() // Button[0] = rgb(random, random, random)... } //Pick a random button at runtime and make it the right guess. let correct = guesses[Math.floor(Math.random() * 3)]; correct.textContent = pickedColor } //Playing the game function guess(pickedColor){ guessArr.forEach((guess) => { guess.addEventListener("click", ()=>{ console.log(guess.textContent); if (playing){ if (guess.textContent == pickedColor){ title.innerHTML = "You Win 🎉" playing = false; document.querySelector("body").style.backgroundColor = pickedColor; } else { title.innerHTML = "YOU LOSE ❌" playing = false; } } }) }); } playAgain.addEventListener("click", init)
问题根源
核心问题是每次调用init()时都会给按钮重复添加点击事件监听器:
- 第一次游戏运行时,按钮绑定了对应第一局
pickedColor的点击事件; - 点击Play Again后,
init()再次调用guess(),又给按钮绑定了新的点击事件(对应新的pickedColor); - 此时按钮上同时存在多轮游戏的事件监听器,点击按钮时会先触发旧事件——旧事件里的
pickedColor是第一局的颜色,和当前按钮的文本(新的正确颜色)不匹配,直接触发YOU LOSE ❌并把playing设为false,后续新事件因为playing为false无法执行。
解决方案
方案1:移除旧事件监听器后再绑定新事件
把点击处理函数抽成独立函数,方便移除和重新绑定:
'use strict' //DOM Elements declaration. const square = document.getElementById("color1") const guesses = document.getElementsByClassName("guess"); const guessArr = [...guesses] const playAgain = document.querySelector(".play-again"); const title = document.getElementById("title") var playing = true; // 声明全局点击处理函数,用于后续移除旧监听器 let clickHandler; init(); function init() { let pickedColor = createColor(); console.log(pickedColor); title.innerHTML = "GUESS THE COLOUR!" square.style.backgroundColor = pickedColor; playing = true; updateGuesses(pickedColor); guess(pickedColor); } function createColor () { let r = Math.floor(Math.random() * 255); let g = Math.floor(Math.random() * 255); let b = Math.floor(Math.random() * 255); let color = `rgb(${r}, ${g}, ${b})` return color } function updateGuesses (pickedColor) { for (let i=0; i < 3; i++){ guesses[i].textContent = createColor() } let correct = guesses[Math.floor(Math.random() * 3)]; correct.textContent = pickedColor } function guess(pickedColor){ // 先移除所有按钮的旧监听器 guessArr.forEach((guess) => { if (clickHandler) { guess.removeEventListener("click", clickHandler); } }); // 定义当前游戏的点击处理逻辑 clickHandler = function() { console.log(this.textContent); if (playing){ if (this.textContent === pickedColor){ title.innerHTML = "You Win 🎉" playing = false; document.querySelector("body").style.backgroundColor = pickedColor; } else { title.innerHTML = "YOU LOSE ❌" playing = false; } } }; // 绑定新的监听器 guessArr.forEach((guess) => { guess.addEventListener("click", clickHandler); }); } playAgain.addEventListener("click", init)
方案2:使用事件委托(推荐)
只在父元素上绑定一次事件,通过事件冒泡判断点击目标,避免重复绑定的问题:
'use strict' //DOM Elements declaration. const square = document.getElementById("color1") // 假设按钮有统一的父容器,若无则可用document.body const guessesContainer = document.querySelector(".guesses-container"); const playAgain = document.querySelector(".play-again"); const title = document.getElementById("title") var playing = true; // 用变量存储当前游戏的正确颜色 let currentPickedColor; init(); function init() { currentPickedColor = createColor(); console.log(currentPickedColor); title.innerHTML = "GUESS THE COLOUR!" square.style.backgroundColor = currentPickedColor; playing = true; updateGuesses(currentPickedColor); } function createColor () { let r = Math.floor(Math.random() * 255); let g = Math.floor(Math.random() * 255); let b = Math.floor(Math.random() * 255); let color = `rgb(${r}, ${g}, ${b})` return color } function updateGuesses (pickedColor) { const guesses = document.getElementsByClassName("guess"); for (let i=0; i < 3; i++){ guesses[i].textContent = createColor() } let correct = guesses[Math.floor(Math.random() * 3)]; correct.textContent = pickedColor } // 仅绑定一次事件委托 guessesContainer.addEventListener("click", function(e) { // 判断点击目标是猜色按钮且游戏正在进行 if (e.target.classList.contains("guess") && playing) { const clickedText = e.target.textContent; console.log(clickedText); if (clickedText === currentPickedColor){ title.innerHTML = "You Win 🎉" playing = false; document.querySelector("body").style.backgroundColor = currentPickedColor; } else { title.innerHTML = "YOU LOSE ❌" playing = false; } } }); playAgain.addEventListener("click", init)
内容的提问来源于stack exchange,提问作者Remel Crowe
相关产品推荐
相关产品推荐

