浏览了 React 官网的 入门教程,完成结尾问题并记录答案。
预览
答案
在游戏历史记录列表显示每一步棋的坐标,格式为 (列号,行号)
首先为 Game
组件的第一个 history state
添加坐标属性 coordinate
。
- class Game extends React.Component {
- constructor(props) {
- super(props);
- this.state = {
- history: [
- {
- squares: Array(9).fill(null),
- coordinate: [0, 0],
- },
- ],
- // ...
- };
- }
- // ...
- }
修改 handleClick
函数,让 Board
每次被点击时,保存自己的坐标。
- class Game extends React.Component {
- // ...
- handleClick(i) {
- //...
- this.setState({
- history: history.concat([
- {
- squares: squares,
- coordinate: [parseInt(i / 3) + 1, (i % 3) + 1],
- },
- ]),
- //...
- });
- }
- //...
- }
最后,在 render
函数中,将当前坐标放到描述中。
- render() {
- const history = this.state.history;
- const moves = history.map((step, move) => {
- const desc = move
- ? "Go to move #" + move + ", coordinate: (" + step.coordinate + ")"
- : "Go to game start";
- // ...
- });
- // ...
- }
在历史记录列表中加粗显示当前选择的项目
修改 Game
组件的 render
函数,如果 <button>
是当前步骤,通过 style
属性让其字体加粗。
- class Game extends React.Component {
- // ...
- render() {
- const moves = history.map((step, move) => {
- return (
- <li key={move}>
- <button
- style={{
- fontWeight: move === this.state.stepNumber ? "bold" : "normal",
- }}
- >
- </button>
- </li>
- );
- });
- }
使用两个循环来渲染出棋盘的格子,而不是在代码里写死(hardcode)
- class Board extends React.Component {
- // ...
- render() {
- const seq = Array(3).fill(null);
- return (
- <div>
- {seq.map((_, i) => (
- <div key={i} className="board-row">
- {seq.map((_, j) => this.renderSquare(3 * i + j))}
- </div>
- ))}
- </div>
- );
- }
- }
添加一个可以升序或降序显示历史记录的按钮
首先在 Game
组件的 state
中添加 升序
属性 ascSteps
。接着改变 render
方法,在 status <div>
后增加一个按钮,内部文字跟随 ascSteps
作相应改变,再为其添加 onClick
属性,点击后调用 reverseMovesOrder
函数,反转 ascSteps
。
接着,在 <ol>
标签中添加 reversed
属性,根据 ascSteps
设置是与否。同时,其 children
也根据 ascSteps
决定是否反转。最后编写 reverseMovesOrder
函数,当它被调用时,改变状态中的 ascSteps
。
- class Game extends React.Component {
- constructor(props) {
- super(props);
- this.state = {
- // ...
- ascSteps: true,
- };
- }
-
- reverseMovesOrder() {
- this.setState({
- ascSteps: !this.state.ascSteps,
- });
- }
-
- render() {
- // ...
- return (
- <div className="game">
- /* ... */
- <div className="game-info">
- <div>{status}</div>
- <button
- onClick={() => this.reverseMovesOrder()}
- >
- {(this.state.ascSteps ? "Descend" : "Ascend") + " step order"}
- </button>
- <ol reversed={this.state.ascSteps ? false : true}>
- {this.state.ascSteps ? moves : moves.reverse()}
- </ol>
- </div>
- </div>
- );
- }
- // ...
- }
每当有人获胜时,高亮显示连成一线的 3 颗棋子
首先,改变 calculateWinnerLine
函数,当有人获胜时,返回整个获胜行。
- function calculateWinnerLine(squares) {
- // ...
- for (let i = 0; i < lines.length; i++) {
- const [a, b, c] = lines[i];
- if (squares[a] && squares[a] === squares[b] && squares[a] === squares[c]) {
- return lines[i];
- }
- }
- return null;
- }
接着,在 Game
组件中,把获胜行传给 Board
组件。
- class Game extends React.Component {
- // ...
-
- render() {
- // ...
- const winnerLine = calculateWinnerLine(current.squares);
- return (
- <div className="game">
- <div className="game-board">
- <Board
- winnerLine={winnerLine}
- />
- </div>
- /* ... */
- </div>
- );
- }
- }
最后,改变 Board
组件的 renderSquare
方法,如果自身包含在获胜行中,则背景设为 yellow
。同时,Square
组件要接收 style
属性,并将其设置到原生 <button>
上。
- class Board extends React.Component {
- renderSquare(i) {
- let bgColor = "white";
- if (this.props.winnerLine && this.props.winnerLine.includes(i)) {
- bgColor = "yellow";
- }
- return (
- <Square
- style={{
- backgroundColor: bgColor,
- }}
- /* ... */
- />
- );
- }
- // ...
- }
-
- function Square(props) {
- return (
- <button style={props.style} /* ... */>
- {props.value}
- </button>
- );
- }
当无人获胜时,显示一个平局的消息
改变 Game
组件的 render
函数,有赢家则显示,如果没有,接着检查方格是否被占满,如果是则为平局,否则显示下个 player
。
- class Game extends React.Component {
- render() {
- const history = this.state.history;
- const current = history[this.state.stepNumber];
- const winnerLine = calculateWinnerLine(current.squares);
- let status;
- if (winnerLine) {
- status = "Winner: " + current.squares[winnerLine[0]];
- } else if (!current.squares.includes(null)) {
- status = "Game over, being a draw";
- } else {
- status = "Next player: " + (this.state.xIsNext ? "X" : "O");
- }
- // ...
- }
- // ...
- }
相关
如有问题请在下方留言,文章转载请注明出处,详细交流请加下方群组!请大佬不要屏蔽文中广告,因为它将帮我分担服务器开支,如果能帮忙点击我将万分感谢。
强调几点:(该留言由系统自动生成!)
1. 请不要刷广告,本站没有流量!
2. 我不回复虚假邮箱,因为回复了你也看不到!
3. 存在必须回复的隐藏内容时,可以直接使用表情框里的阿鲁表情!