react之实例:井字棋游戏(直接引用react)

1.分析需求

react之实例:井字棋游戏(直接引用react)_第1张图片 演示链接地址

井字棋游戏,两位玩家,分别是‘O’ 和 ‘X’ 分别落子,先完成三点一线的获胜,也就是无论横、竖、斜连成一条直线

组件拆分

  1. 棋子组件,共九个棋子
  2. 棋盘组件,九个方格形成棋盘
  3. 游戏组件,包括棋盘、下个玩家,还有游戏记录(可以悔棋)

2.页面搭建

引入必要js以及css


<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>井字棋游戏第一步title>
    <script src="react.js">script>
    <script src="react-dom.js">script>
    <script src="browser.min.js">script>
    <style>
        body {
            font: 14px "Century Gothic", Futura, sans-serif;
            margin: 20px;
        }

        ol, ul {
            padding-left: 30px;
        }

        .board-row:after {
            clear: both;
            content: "";
            display: table;
        }

        .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;
        }

    style>
head>
<body>
    <div id="root">div>
body>
<script type="text/babel">

script>
html>

接下来的所有代码都在script中进行

3.第一步:创建组件

class Square extends React.Component{ //棋子组件
        constructor(){
            super()
        }
        render(){
            return(
                
            )
        }
    }
    class Board extends React.Component{  //棋盘组件
        renderSquare(i){
            return(
                
            )
        }
        render() {
            return (
                <div>
                    <div className="board-row">
                        {this.renderSquare(0)}
                        {this.renderSquare(1)}
                        {this.renderSquare(2)}
                    div>
                    <div className="board-row">
                        {this.renderSquare(3)}
                        {this.renderSquare(4)}
                        {this.renderSquare(5)}
                    div>
                    <div className="board-row">
                        {this.renderSquare(6)}
                        {this.renderSquare(7)}
                        {this.renderSquare(8)}
                    div>
                div>
            );
        }
    }
    class Game extends React.Component{ //游戏组件
        render(){
            return(
                <div className="game">
                    <div className="game-board">
                        
                    div>
                    <div className="game-info">
                        <div>Next Player:div> {/*显示下一步玩家*/}
                        
    {/*显示历史记录*/} div> div> ) } } ReactDOM.render( , document.getElementById('root') )

    这一步创建了三个类组件
    显示结果:react之实例:井字棋游戏(直接引用react)_第2张图片 参考链接

    注:在render()内的JSX语法 注释要写成 {/*注释内容*/}

    第一步只将所有内容展示出来,并未加入任何事件


    4.第二步:添加棋子点击事件

    class Square extends React.Component{ //棋子组件
            constructor(){
                super();
                this.state = {
                    value:null
                }
            }
            render(){
                return(
                    
                )
            }
        }

    修改Square组件,默认棋子是空值,点击添加‘X’,由于这个值是交互式的,所以把value放在state内

    显示结果:react之实例:井字棋游戏(直接引用react)_第3张图片 参考链接


    5.第三步:状态提升

    将Square的state提到父组件Board里,以props传入Square,使其父子组件同步

        function Square(props) {//棋子组件
                return(
                        
            )
        }
        class Board extends React.Component{  //棋盘组件
            constructor(){
                super();
                this.state = {
                    squares :Array(9).fill(null)
                };
            }
    
            handleClick(i){
                const squares = this.state.squares.slice();//将原数组复制一份,为了之后做悔棋
                squares[i] = 'X';
                this.setState({squares: squares});
            }
            renderSquare(i){
                return(
                    this.state.squares[i]} onClick={() =>this.handleClick(i)}/>  /*将value和事件以props形式传入子组件*/
                )
            }
            render() {
                return (
                    <div>
                        <div className="board-row">
                            {this.renderSquare(0)}
                            {this.renderSquare(1)}
                            {this.renderSquare(2)}
                        div>
                        <div className="board-row">
                            {this.renderSquare(3)}
                            {this.renderSquare(4)}
                            {this.renderSquare(5)}
                        div>
                        <div className="board-row">
                            {this.renderSquare(6)}
                            {this.renderSquare(7)}
                            {this.renderSquare(8)}
                        div>
                    div>
                );
            }
        }

    当您要聚合来自多个子节点的数据 或 使两个子组件之间相互通信时,提升 state(状态) ,使其存储在父组件中。父组件可以通过 props(属性) 把 state(状态) 传递回子组件,以使子组件始终与父组件同步。
    如果组件中只包含一个render方法,可以将其改写为函数式组件,传入props即可

    参考链接


    6.第四步:轮流下棋、宣布获胜者

    在第三步中只有一名玩家‘X’,先在添加一名‘O’,在state添加 xIsNext属性,用来判断下一位玩家是不是‘X’,在script添加获胜判断函数,并在handleClick中调用

    轮流下棋

    class Board extends React.Component{  //棋盘组件
            constructor(){
                super();
                this.state = {
                    squares :Array(9).fill(null),
                    xIsNext: true,
                };
            }
    
            handleClick(i){
                const squares = this.state.squares.slice();//将原数组复制一份,为了之后做悔棋
                squares[i] = this.state.xIsNext?'X':'O';
                this.setState({
                    squares: squares,
                    xIsNext: !this.state.xIsNext,
                });
            }
            renderSquare(i){
                return(
                    this.state.squares[i]} onClick={() =>this.handleClick(i)}/>  /*将value和事件以props形式传入子组件*/
                )
            }
            render() {
                const status = 'Next player:' + (this.state.xIsNext?'X':'O');
                return (
                    <div>
                        <div className="status">{status}div>
                        <div className="board-row">
                            {this.renderSquare(0)}
                            {this.renderSquare(1)}
                            {this.renderSquare(2)}
                        div>
                        <div className="board-row">
                            {this.renderSquare(3)}
                            {this.renderSquare(4)}
                            {this.renderSquare(5)}
                        div>
                        <div className="board-row">
                            {this.renderSquare(6)}
                            {this.renderSquare(7)}
                            {this.renderSquare(8)}
                        div>
                    div>
                );
            }
        }

    宣布获胜者

    class Board extends React.Component{  //棋盘组件
            constructor(){
                super();
                this.state = {
                    squares :Array(9).fill(null),
                    xIsNext: true,
                };
            }
    
            handleClick(i){
    
                const squares = this.state.squares.slice();//将原数组复制一份,为了之后做悔棋
                if (calculateWinner(squares) || squares[i]) {
                    return;
                }
                squares[i] = this.state.xIsNext?'X':'O';
                this.setState({
                    squares: squares,
                    xIsNext: !this.state.xIsNext,
                });
            }
            renderSquare(i){
                return(
                    this.state.squares[i]} onClick={() =>this.handleClick(i)}/>  /*将value和事件以props形式传入子组件*/
                )
            }
            render() {
                const winner = calculateWinner(this.state.squares);
                let status;
                if (winner) {
                    status = 'Winner: ' + winner;
                } else {
                    status = 'Next player: ' + (this.state.xIsNext ? 'X' : 'O');
                }
                return (
                    <div>
                        <div className="status">{status}div>
                        <div className="board-row">
                            {this.renderSquare(0)}
                            {this.renderSquare(1)}
                            {this.renderSquare(2)}
                        div>
                        <div className="board-row">
                            {this.renderSquare(3)}
                            {this.renderSquare(4)}
                            {this.renderSquare(5)}
                        div>
                        <div className="board-row">
                            {this.renderSquare(6)}
                            {this.renderSquare(7)}
                            {this.renderSquare(8)}
                        div>
                    div>
                );
            }
        }
        function calculateWinner(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 squares[a];
                }
            }
            return null;
        }

    参考链接


    7.第五步:存储历史记录

    将Board中的state提升到Game,并将Board中的this.state改为this.props

    class Board extends React.Component{  //棋盘组件
    
            renderSquare(i){
                return(
                    this.props.squares[i]} onClick={() =>this.props.onClick(i)}/>  /*将value和事件以props形式传入子组件*/
                )
            }
            render() {
                return (
                    <div>
                        <div className="board-row">
                            {this.renderSquare(0)}
                            {this.renderSquare(1)}
                            {this.renderSquare(2)}
                        div>
                        <div className="board-row">
                            {this.renderSquare(3)}
                            {this.renderSquare(4)}
                            {this.renderSquare(5)}
                        div>
                        <div className="board-row">
                            {this.renderSquare(6)}
                            {this.renderSquare(7)}
                            {this.renderSquare(8)}
                        div>
                    div>
                );
            }
        }

    将state以及事件放进Game组件

    class Game extends React.Component {
            constructor(props) {
                super(props);
                this.state = {
                    history: [
                        {
                            squares: Array(9).fill(null)
                        }
                    ],
                    stepNumber: 0,
                    xIsNext: true
                };
            }
    
            handleClick(i) {
                const history = this.state.history.slice(0, this.state.stepNumber + 1);
                const current = history[history.length - 1];
                const squares = current.squares.slice();
                if (calculateWinner(squares) || squares[i]) {
                    return;
                }
                squares[i] = this.state.xIsNext ? "X" : "O";
                this.setState({
                    history: history.concat([
                        {
                            squares: squares
                        }
                    ]),
                    stepNumber: history.length,
                    xIsNext: !this.state.xIsNext
                });
            }
    
            jumpTo(step) {
                this.setState({
                    stepNumber: step,
                    xIsNext: (step % 2) === 0,
    
                });
                if(step == 0){
                    this.setState({
                        history: [
                            {
                                squares: Array(9).fill(null)
                            }
                        ]
                    });
                }
    
            }
    
            render() {
                const history = this.state.history;
                const current = history[this.state.stepNumber];
                const winner = calculateWinner(current.squares);
    
                const moves = this.state.history.map((step, move) => {
                    const desc = move ?
                        'Go to move #' + move :
                        'restart';
                    return (
                        
  1. ); }); let status; if (winner) { status = "Winner: " + winner; } else { status = "Next player: " + (this.state.xIsNext ? "X" : "O"); } return ( <div className="game"> <div className="game-board"> this.handleClick(i)} /> div> <div className="game-info"> <div>{status}div>
      {moves}
    div> div> ); } }

    你可能感兴趣的:(react)