You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

井字棋开发:如何仅在游戏未结束时触发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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.07 10:10:15