React官方教程三子棋游戏(Tic Tac Toe)改进完善

React Tic Tac Toe 教程地址

React官方教程三子棋游戏(Tic Tac Toe)改进完善_第1张图片

改进内容:

  1. 在游戏历史记录列表显示每一步棋的坐标,格式为 (列号, 行号)。
  2. 在历史记录列表中加粗显示当前选择的项目。
  3. 使用两个循环来渲染出棋盘的格子,而不是在代码里写死(hardcode)。
  4. 添加一个可以升序或降序显示历史记录的按钮。
  5. 每当有人获胜时,高亮显示连成一线的 3 颗棋子。
  6. 当无人获胜时,显示一个平局的消息。

最终效果:

  • 坐标,加粗当前,循环,获胜高亮
    React官方教程三子棋游戏(Tic Tac Toe)改进完善_第2张图片
  • 历史记录升降
    React官方教程三子棋游戏(Tic Tac Toe)改进完善_第3张图片
  • 平局
    React官方教程三子棋游戏(Tic Tac Toe)改进完善_第4张图片


实现代码 - codepen预览

Javascript:

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';

function Square(props) {
    return (
        
    );
}

class Board extends React.Component {

    isWinnerSquare(i) {
        if(this.props.winner && this.props.winner.line.findIndex(el => el === i) !== -1) {
            return true;
        }
        return null;
    }

    renderSquare(i) {
        return (
             this.props.onClick(i)}
                winner={this.isWinnerSquare(i)}
                key={i}
            />
        );
    }

    render() {
        return (
            
1
2
3
{ Array(3).fill(null).map((row, x) => { return (
{ Array(3).fill(null).map((square, y) => this.renderSquare(3 * x + y)) }
) }) }
a
b
c
); } } class Game extends React.Component { constructor(props) { super(props); this.state = { history: [ { squares: Array(9).fill(null), position: null, } ], XIsNext: true, stepNumber: 0, historyReverse: false, } } handleClick(i) { const history = this.state.history.slice(0, this.state.stepNumber + 1); const current = history[history.length - 1]; const squares = current.squares.slice(); const position = getPosition(i); // 当有玩家胜出时,或者某个 Square 已经被填充时,该函数不做任何处理直接返回。 if (caculateWinner(squares) || squares[i]) { return; } squares[i] = this.state.XIsNext ? 'X' : 'O'; this.setState({ history: history.concat([{ squares, position, }]), XIsNext: !this.state.XIsNext, stepNumber: history.length, }); } jumpTo(step) { this.setState({ stepNumber: step, XIsNext: (step % 2) === 0, }); } historyReverse() { this.setState({ historyReverse: !this.state.historyReverse, }); } render() { const history = this.state.history; const current = history[this.state.stepNumber]; const winner = caculateWinner(current.squares); const moves = history.map((step, move) => { const desc = move ? 'Go to move #' + move + ` ( ${history[move].position.join(',')} )` : 'Go to game start'; const bold = move === this.state.stepNumber ? 'bold' : ''; return (
  • ); }) let movesView = this.state.historyReverse ? moves.reverse() : moves; let status; if (winner) { status = 'Winner: ' + winner.name; } else if(this.state.stepNumber === 9) { status = `Draw!`; } else { status = `Next player: ${ this.state.XIsNext ? 'X' : 'O'}`; } // console.log(history) return (
    this.handleClick(i)} />
    {status}
      {movesView}
    ); } } // ======================================== ReactDOM.render( , document.getElementById('root') ); // 传入长度为 9 的数组,此函数将判断出获胜者,并根据情况返回 “X”,“O” 或 “null”。 function caculateWinner(squares) { const lines = [ [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 (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 { name: squares[a], line: lines[i], }; } } return null; } function getPosition(i) { const rowMap = [ ['a', 3], ['b', 3], ['c', 3], ['a', 2], ['b', 2], ['c', 2], ['a', 1], ['b', 1], ['c', 1], ] return rowMap[i]; }

    css:

    body {
        font: 14px "Century Gothic", Futura, sans-serif;
        margin: 20px;
    }
    
    ol,
    ul {
        padding-left: 30px;
    }
    
    .board{
        counter-reset: row;
        position: relative;
        padding-left: 34px;
    }
    .board-row:after {
        clear: both;
        content: "";
        display: table;
    }
    
    .row-counters {
        display: flex;
        flex-flow: column-reverse nowrap;
        position: absolute;
        left: 0;
        top: 0;
    }
    .row-num {
        width: 34px;
        height: 34px;
        font-size: 20px;
        /* font-weight: bold; */
        line-height: 34px;
        padding: 0;
        text-align: center;
    }
    .column-counters {
        display: flex;
    }
    .column-num {
        width: 34px;
        height: 34px;
        font-size: 20px;
        /* font-weight: bold; */
        line-height: 34px;
        padding: 0;
        text-align: center;
    }
    
    .status {
        margin-bottom: 10px;
    }
    
    .square {
        background: #fff;
        border: 1px solid #999;
        float: left;
        font-size: 24px;
        font-weight: bold;
        line-height: 34px;
        height: 34px;
        margin-right: -1px;
        margin-top: -1px;
        padding: 0;
        text-align: center;
        width: 34px;
    }
    
    .square:focus {
        outline: none;
    }
    
    .kbd-navigation .square:focus {
        background: #ddd;
    }
    
    .game {
        display: flex;
        flex-direction: row;
    }
    
    .game-info {
        margin-left: 20px;
    }
    
    .bold {
        font-weight: bold;
    }
    .bold button {
        font-weight: bold;
    }
    .gold {
        background: gold;
    }

    你可能感兴趣的:(react.js,javascript,前端)