RestartClicked()触发异常:井字棋重启后Enter键行为异常求助
井字棋方向键控制重启后Enter键异常问题
我正在做学校的井字棋项目,鼠标操作版本完全正常,现在改成方向键控制。页面首次加载/刷新时功能正常,但点击Restart按钮重置所有值后,Enter键会随机重置红框位置,同时数组每次只填充一个值且重复操作。尝试了多种调试方法没解决,求找出原因。
方向键处理函数
function keyDown(e) { console.log(e.keyCode); let prevBox = boxes[prevActive]; prevBox.style.backgroundColor = ""; switch (e.keyCode) { //right arrow key case 39: xPos = xPos < 2 ? xPos + 1 : xPos = 0; break; //left arrow key case 37: xPos = xPos > 0 ? xPos - 1 : xPos = 2; break; // down arrow key case 40: yPos = yPos < 2 ? yPos + 1 : yPos = 0; break; // up arrow key case 38: yPos = yPos > 0 ? yPos - 1 : yPos = 0; break; } console.log([xPos, yPos]); active = yPos * 3 + xPos; redBox = boxes[active].style.backgroundColor = "red"; console.log(active); prevActive = active; prevBox = boxes[prevActive]; if (e.keyCode == 13) { if(!spaces[active]) { spaces[active] = currentPlayer; boxes[active].innerText = currentPlayer; currentPlayer = currentPlayer == letterX ? letterO : letterX; if (winner() !== false) { playerText = `${currentPlayer} has won!` let winCombo = winner(); console.log(winCombo); } } } }
Restart按钮函数
restartBtn.addEventListener('click', restartClicked); function restartClicked() { spaces.fill(null); boxes.forEach( box => { box.innerText = ''; box.style.backgroundColor = ""; }); boxes[0].style.backgroundColor = "red"; active = 0; prevActive = 0; xPos = 0; yPos = 0; currentPlayer = letterX } startGame();
HTML文件
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <link rel="stylesheet" href="style.css"> </head> <body> <div class="container"> <h1 id="tictactoe">Tic Tac Toe</h1> <button id="restartBtn">Restart</button> <div id="gameTable"> <div class="box" id="0"></div> <div class="box" id="1"></div> <div class="box" id="2"></div> <div class="box" id="3"></div> <div class="box" id="4"></div> <div class="box" id="5"></div> <div class="box" id="6"></div> <div class="box" id="7"></div> <div class="box" id="8"></div> </div> <h1 id="currentPlayerTxt"></h1> <script src="index2.js"></script> </div> </body> </html>
CSS文件
@font-face { font-family: 'Nunito'; src: url('Fonts/Nunito-Regular.ttf'); } html, body { height: 100%; font-family: 'Nunito'; } body { display: flex; justify-content: center; align-items: center; margin: 0; background-color: #c2415d; } .boxContainer { position: relative; display: flex; flex-direction: column; align-items: center; width: 400px; height: 450px; background-color: lightgray; margin: 10px; border-radius: 50px; } .boxBtn { font-size: 50px; background-color:rgb(255, 0, 0); line-height: 60px; width: 60%; font-size: 24px; user-select: none; color: rgb(255, 255, 255); text-align: center; border-radius: 50px; } a { text-decoration: none; color: inherit } #tictactoe { color: #ffffff; } #gameTable { width: 450px; display: flex; flex-wrap: wrap; margin-top: 40px; background-color: #ffffff; } .box { height: 150px; width: 150px; display: flex; align-items: center; justify-content: center; font-size: 120px; outline: 2px solid; border-bottom: 2px solid; user-select: none; } .box:nth-child(6) ~ .box { border-bottom: none; }
期望结果
重启后的行为与页面首次加载时一致,红框位置正常更新,Enter键不会出现异常重置的情况。
问题原因及修复
核心问题
- Enter键触发了红框重置逻辑:当前
keyDown函数中,不管按下的是方向键还是Enter键,都会先执行清除上一个红框、重新计算位置并设置红框的代码。但Enter键并不改变xPos/yPos,这会导致代码错误地重复设置当前active位置,加上Restart后变量状态的微小偏差,引发异常。 - Restart按钮获取焦点导致按键冲突:点击Restart按钮后,按钮会获得焦点,此时按下Enter会触发按钮的点击事件(相当于再次Restart),这是另一个隐性异常源。
修复方案
1. 拆分方向键与Enter键逻辑
修改keyDown函数,仅在按下方向键时执行红框移动代码,Enter键单独处理落子:
function keyDown(e) { console.log(e.keyCode); // 仅方向键触发红框移动 if ([37, 38, 39, 40].includes(e.keyCode)) { let prevBox = boxes[prevActive]; prevBox.style.backgroundColor = ""; switch (e.keyCode) { case 39: // 右箭头 xPos = xPos < 2 ? xPos + 1 : 0; break; case 37: // 左箭头 xPos = xPos > 0 ? xPos - 1 : 2; break; case 40: // 下箭头 yPos = yPos < 2 ? yPos + 1 : 0; break; case 38: // 上箭头 yPos = yPos > 0 ? yPos - 1 : 0; break; } console.log([xPos, yPos]); active = yPos * 3 + xPos; boxes[active].style.backgroundColor = "red"; console.log(active); prevActive = active; } // Enter键单独处理落子 if (e.keyCode === 13) { if (!spaces[active]) { spaces[active] = currentPlayer; boxes[active].innerText = currentPlayer; currentPlayer = currentPlayer === letterX ? letterO : letterX; if (winner() !== false) { playerText = `${currentPlayer} has won!` let winCombo = winner(); console.log(winCombo); } } } }
2. 消除Restart按钮焦点冲突
在restartClicked函数末尾添加代码,将焦点从按钮移开:
function restartClicked() { spaces.fill(null); boxes.forEach( box => { box.innerText = ''; box.style.backgroundColor = ""; }); boxes[0].style.backgroundColor = "red"; active = 0; prevActive = 0; xPos = 0; yPos = 0; currentPlayer = letterX; // 移除按钮焦点,避免Enter触发重复Restart restartBtn.blur(); // 可选:将焦点移到游戏容器,确保按键事件正常监听 document.getElementById('gameTable').focus(); }
内容的提问来源于stack exchange,提问作者Slam4
相关产品推荐
相关产品推荐

