React井字棋开发问题:如何仅为获胜棋子添加颜色?
React井字棋问题:仅高亮获胜棋子而非全部同色棋子
我用React开发的井字棋游戏功能正常,能正确识别胜者,但存在一个问题:当玩家X获胜时,所有X棋子都会被染成绿色,而非仅将获胜的三个X标绿。我希望只给获胜的棋子添加绿色样式,试过用状态存储颜色但会导致所有棋子变色,也知晓不能直接操作DOM。以下是主组件Grid和Box组件的代码:
主组件Grid代码
export default function Grid() { // Game state const [grid, setGrid] = useState(new Array(9).fill("")); const [turn, setTurn] = useState("P1") //toggle turns for P1 and P2 const [color, setColor] = useState("black") // Players state const [countWinP1, setCountWinP1] = useState(0) const [countWinP2, setCountWinP2] = useState(0) const handleClick = (event) => { const clickValue = event.target.value setGrid(grid.map((btn, index) => { if (index+1 == clickValue && turn === "P1") { return btn = "X" } else if (index+1 == clickValue && turn === "P2") { return btn = "0" } return btn })) handleToggle(); } // WIN COUNT useEffect(() => { const newCountP1 = countWinP1 + 1; const newCountP2 = countWinP2 + 1; if (handleWinner(grid) && turn === "P2") { setCountWinP1(newCountP1); } else if (handleWinner(grid) && turn === "P1") { setCountWinP2(newCountP2); } }, [grid]); // RESETS const handleToggle = () => { if (turn === "P1") { setTurn("P2") } else { setTurn("P1") } } const handleReset = () => { setGrid(new Array(9).fill(0)); setTurn("P1") } const handlePlayersReset = () => { setCountWinP1(0) setCountWinP2(0) } return ( <> <WinCount countWinP1={countWinP1} countWinP2={countWinP2} PlayersReset={handlePlayersReset}/> <Box grid={grid} handleClick={handleClick} handleWinner={handleWinner(grid)} handleReset={handleReset} turn={turn} color={color}/> </> ) }
Box组件代码
export default function Box({grid, handleClick, handleWinner, handleReset, turn, color}) { return ( <> <div className='container'> <h1> {handleWinner && turn==="P2" ? "WINNER: PLAYER 1" : handleWinner && turn==="P1" ? "WINNER: PLAYER 2" : "GAME ON"} </h1> <div className='box'> {grid.map((btn, index) => { if (btn === "X") { return <button id={index+1} key={uuid()} value={index+1} onClick={handleClick} disabled={true}><strong style={{fontSize:30, color: handleWinner && turn=== "P2"? "green" : handleWinner && turn=== "P1" ? "red" : "black" }}>X</strong></button> } else if (btn === "0") { return <button id={index+1} key={uuid()} value={index+1} onClick={handleClick} disabled={true}><strong style={{fontSize:30, color: handleWinner && turn=== "P1"? "green" : handleWinner && turn=== "P2" ? "red" : "black" }}>0</strong></button> } else return <button id={index+1} key={uuid()} value={index+1} onClick={handleClick} disabled={handleWinner? true : false}>Click me</button> })} </div> <button className="grid_reset" onClick={handleReset}>RESET</button> </div> </> ) }
解决方案
问题核心在于你当前的handleWinner函数只返回布尔值,无法区分哪些棋子是获胜序列的一部分。我们需要修改它返回获胜棋子的索引数组,再基于这个数组判断每个棋子是否需要高亮。
步骤1:修改handleWinner函数,返回获胜索引数组
补充或修改handleWinner函数,让它返回获胜的三个棋子索引,没有胜者则返回null:
const handleWinner = (grid) => { // 所有可能的获胜组合(对应网格的索引) const winPatterns = [ [0,1,2], [3,4,5], [6,7,8], // 横向 [0,3,6], [1,4,7], [2,5,8], // 纵向 [0,4,8], [2,4,6] // 对角线 ]; // 遍历所有获胜组合 for (const pattern of winPatterns) { const [a, b, c] = pattern; // 判断三个位置的棋子是否相同且不为空 if (grid[a] && grid[a] === grid[b] && grid[a] === grid[c]) { return pattern; // 返回获胜的索引数组 } } return null; // 无胜者 };
步骤2:在Grid组件中存储获胜索引状态
添加状态存储获胜棋子的索引数组,并更新useEffect的逻辑:
// 在Grid组件的状态中添加 const [winningIndices, setWinningIndices] = useState(null); // 修改原有的useEffect useEffect(() => { const winningCells = handleWinner(grid); if (winningCells) { setWinningIndices(winningCells); // 用函数式更新计数,避免依赖问题 if (turn === "P2") { setCountWinP1(prev => prev + 1); } else { setCountWinP2(prev => prev + 1); } } else { setWinningIndices(null); } }, [grid, turn]); // 修改Box组件的props,传入winningIndices而非handleWinner布尔值 <Box grid={grid} handleClick={handleClick} winningIndices={winningIndices} handleReset={handleReset} turn={turn} />
步骤3:修改Box组件,根据获胜索引判断颜色
更新Box组件的渲染逻辑,仅给获胜索引内的棋子标绿:
export default function Box({grid, handleClick, winningIndices, handleReset, turn}) { // 判断是否有胜者 const hasWinner = !!winningIndices; return ( <> <div className='container'> <h1> {hasWinner && turn==="P2" ? "WINNER: PLAYER 1" : hasWinner && turn==="P1" ? "WINNER: PLAYER 2" : "GAME ON"} </h1> <div className='box'> {grid.map((btn, index) => { let textColor = "black"; // 如果当前棋子在获胜索引数组中,标绿 if (winningIndices && winningIndices.includes(index)) { textColor = "green"; } // 如果有胜者但当前棋子不在获胜序列中,标红(可根据需求调整) else if (hasWinner) { textColor = "red"; } if (btn === "X") { return ( <button id={index+1} key={uuid()} value={index+1} onClick={handleClick} disabled={true}> <strong style={{fontSize:30, color: textColor}}>X</strong> </button> ); } else if (btn === "0") { return ( <button id={index+1} key={uuid()} value={index+1} onClick={handleClick} disabled={true}> <strong style={{fontSize:30, color: textColor}}>0</strong> </button> ); } else { return ( <button id={index+1} key={uuid()} value={index+1} onClick={handleClick} disabled={hasWinner}> Click me </button> ); } })} </div> <button className="grid_reset" onClick={handleReset}>RESET</button> </div> </> ) }
步骤4:修复其他小问题
handleReset中setGrid(new Array(9).fill(0))改为setGrid(new Array(9).fill("")),和初始状态保持一致- 移除无用的
color状态,因为现在不需要全局控制颜色
内容的提问来源于stack exchange,提问作者MirunaB
相关产品推荐
相关产品推荐

