井字棋开发:如何仅在游戏未结束时触发Box元素hover变色
问题解决:井字棋游戏结束后禁用hover背景色变化
问题描述
开发井字棋游戏时,期望仅在游戏未结束(无玩家获胜且未平局)时,类名为boxes的元素在鼠标hover时切换背景色:
- 鼠标移入:当前玩家为X时显示偏红背景色
rgb(215 175 175),为O时显示偏蓝背景色rgb(175 215 193) - 鼠标移出:恢复默认背景色
rgb(222, 238, 225)
但当前代码在游戏结束(玩家获胜或平局)后,hover仍会触发颜色变化,不符合预期。
问题根源
你原来的代码仅在startgame初始化时判断一次游戏状态,然后绑定mouseenter和mouseleave事件。但事件一旦绑定就会持续生效,即使后续游戏结束,事件回调依然会执行。同时,你使用的判断条件(playerhaswon() == false) || (checkDraw() == false)逻辑错误,只要游戏没赢或者没平局就会绑定事件,而游戏开始时两者都为false,事件会被绑定,但游戏结束后不会自动移除。
解决方案
不需要在初始化时判断状态再绑定事件,而是在事件回调内部实时检查游戏状态,只有游戏未结束时才执行颜色变化逻辑。这样无论游戏处于什么阶段,hover时都会先判断状态,符合预期。
修改后的核心代码片段
替换你原来startgame中的事件绑定部分为以下代码:
boxes.forEach(box => { // 鼠标移入事件 box.addEventListener("mouseenter", () => { // 仅当游戏未结束时才切换背景色 if (playerhaswon() === false && checkDraw() === false) { box.style.backgroundColor = current_player === X_text ? "rgb(215 175 175)" : "rgb(175 215 193)"; } }); // 鼠标移出事件 box.addEventListener("mouseleave", () => { // 仅当游戏未结束时才恢复默认背景色 if (playerhaswon() === false && checkDraw() === false) { box.style.backgroundColor = "rgb(222, 238, 225)"; } }); });
完整修改后的代码
boxes = Array.from(document.getElementsByClassName("boxes")) reset = document.getElementById("restart_btn") wintext = document.getElementById("winning_text") const X_text = "X" const O_text = "O" let current_player = X_text const startgame = () => { // 绑定hover事件,回调内判断游戏状态 boxes.forEach(box => { box.addEventListener("mouseenter", () => { if (playerhaswon() === false && checkDraw() === false) { box.style.backgroundColor = current_player === X_text ? "rgb(215 175 175)" : "rgb(175 215 193)"; } }); box.addEventListener("mouseleave", () => { if (playerhaswon() === false && checkDraw() === false) { box.style.backgroundColor = "rgb(222, 238, 225)"; } }); }); boxes.forEach(box => { box.addEventListener("click", e => { if (playerhaswon() === false) { const id = e.target.id; if (e.target.innerText === "") { e.target.style.color = current_player == X_text ? "red" : "green" e.target.innerText = current_player; if (playerhaswon() !== false) { wintext.innerHTML = `${current_player} has won`; let winning_blocks = playerhaswon(); for (const num of winning_blocks) { boxes[num].style.backgroundColor = current_player == X_text?"rgb(215 175 175)":"rgb(175 215 193)"; } } else if (checkDraw()) { wintext.innerHTML = "Draw!"; } else { current_player = current_player == X_text ? O_text : X_text; } } } }); }); }; const winning_combos = [ [0, 1, 2], [3, 4, 5], [6, 7, 8], [0, 3, 6], [1, 4, 7], [2, 5, 8], [0, 4, 8], [2, 4, 6] ]; function playerhaswon() { for (const condition of winning_combos) { let [a, b, c] = condition; if ( boxes[a].innerText && (boxes[a].innerText == boxes[b].innerText && boxes[a].innerText == boxes[c].innerText) ) { return [a, b, c]; } } return false; } function checkDraw() { for (let i = 0; i < 9; i++) { if (boxes[i].innerText === "") { return false; } } if (playerhaswon() === false) { return true; } return false; } function resetit() { boxes.forEach(box => { box.innerHTML = ""; box.style.backgroundColor = ""; }); current_player = X_text; wintext.innerHTML = "Tic Tac Toe"; } reset.addEventListener("click", () => resetit()); startgame();
说明
- 事件回调内的
playerhaswon() === false && checkDraw() === false确保只有游戏未结束时才执行颜色变化 - 无需在游戏结束时手动移除事件,因为每次hover都会实时检查状态
- 重置游戏时,事件依然有效,无需重新绑定
内容的提问来源于stack exchange,提问作者Sibty
相关产品推荐
相关产品推荐

