React入门-井字游戏实现与完善

栏目: 服务器 · 发布时间: 5年前

内容简介:前段时间换了家外企工作, 空闲时间比较多。虽然我是做Java后端的,但是老外喜欢搞敏捷开发和全栈,所以也要写前端,既然是老外,那肯定是喜欢用React的,然而我之前从来没写过React,只能从基础一步一步来了。井字游戏是React官方的入门实战教程的案例来的,在这里。

前段时间换了家外企工作, 空闲时间比较多。

虽然我是做 Java 后端的,但是老外喜欢搞敏捷开发和全栈,所以也要写前端,既然是老外,那肯定是喜欢用React的,然而我之前从来没写过React,只能从基础一步一步来了。

井字游戏

井字游戏是React官方的入门实战教程的案例来的,在这里。

这个游戏的规则是这样的:

  • 一共9个格子的棋盘, 共2种棋子,分别是X和O
  • 每次,一个玩家将棋子下到一个格子上
  • 如果有3个相同棋子在横/竖/对角线上相连,那就赢了,否则就为和局

最后的效果是这样的:

React入门-井字游戏实现与完善

实现

我的实现就是完全跟着官方教程来的,最后挑了一些有趣的课后作业完成,分别新增了下面的功能:

  • 点击历史列表某一项时,这一项的文字加粗
  • 将原来硬编码写的九宫格改成用循环
  • 如果是平局,在界面上显示出来

都是比较简单的功能,我还想到了一个功能,就是给一个回放的按钮,点击可以回放整个游戏过程。

所以,增加了上面的4个功能的实现,最终的效果变成:

React入门-井字游戏实现与完善

点击历史列表某一项时,这一项的文字加粗

在state里面加一个字段selectedIndex,表明现在选择的是哪一个历史项,这个字段会在渲染的时候使用。

this.state = {
      history: [
        {
          squares: Array(9).fill(null),
        },
      ],
      currentStep: 0,
      selectedIndex: -1,
      xIsNext: true
    };
复制代码

在渲染的时候,代码改成这样:

const moves = history.map((item, index) => {
      const desc = index > 0 ? `Go to move ${index}` : `Go to game start`
      const textHtml = this.state.selectedIndex === index ? (<b>{desc}</b>) : desc
      return (
        <li key={index}>
          <button onClick={() => this.jumpTo(index)}>{textHtml}</button>
        </li>
      )
    })
复制代码

在生成整个历史列表时,要遍历每一项,这个时候,判断状态里面保存的选择的下标是不是跟某一项的下标相等,如果相等就在文字外面包一个加粗的标签。

在点击某一项时,需要设置selectedIndex的值,代码变成这样子:

jumpTo(i) {
    this.setState({
      currentStep: i,
      selectedIndex: i,
      xIsNext: (i & 1) === 0
    });
  }
复制代码

将原来硬编码写的九宫格改成用循环

这里有点坑,本来我想用双重循环的,比如这样:

let board = []
    for (let i = 0; i < 3; ++i) {
      board.push(<div className="board-row">)
      for (let j = 0; j < 3; ++j) {
        board.push((j) => {this.renderSquare(i * 3 + j)})
      }
      board.push(</div>)
    }
    return (
      <div>
        {board}
      </div>
    );
复制代码

但是在这一行:

board.push(<div className="board-row">)
复制代码

它认为我没闭合标签,认为下面的代码还是内容,会报错, 所以最后我只能改成用map来写了,双重循环应该是可以的,刚入门,不熟悉。

最后用map实现的代码长这样:

let board = []
    for (let i = 0; i < 3; ++i) {
      board.push(
        <div className="board-row">
        {[0, 1, 2].map((j) => this.renderSquare(i * 3 + j))}
        </div>
      )
    }
    return (
      <div>
        {board}
      </div>
    );
复制代码

如果是平局,在界面上显示出来

这个很简单,直接加一个判断,如果没有计算出来winner,并且全部棋子都摆满了棋盘,就认为是平局。代码如下:

if (winner) {
      status = `Winner: ${winner}`
    } else if (history.length > 9) {
      status = `No Winner, it's draw`
    }
复制代码

回放功能

实现也比较简单,思路就是用history保存的状态,用setInterval重新设置一遍,在遍历到最后一个状态时用clearInterval停止。

首先,加个按钮:

<div className="game-info">
          <div>{status}</div>
          <ol>{moves}</ol>
          <div><button onClick={() => this.playBack()}>Play back</button></div>
        </div>
复制代码

然后看这个按钮调用的逻辑:

playBack() {
    this.setState({
      currentStep: 0,
      selectedIndex: 0,
      xIsNext: true
    });
    var intervalID = setInterval(() => {
      this.setState({
        currentStep: this.state.currentStep + 1,
        selectedIndex: this.state.selectedIndex + 1,
        xIsNext: (this.state.currentStep & 1) === 0
      });     
      if (this.state.currentStep >= this.state.history.length - 1) {
        clearInterval(intervalID);
        this.setState({
          xIsNext: (this.state.currentStep & 1) === 0
        })
      }
    }, 1000)
  }
复制代码

整个实现就是这样的了! 忘了要把源码附上,在 这里

本文首发于我的博客。


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

单元测试之道Java版

单元测试之道Java版

David Thomas、Andrew Hunt / 陈伟柱、陶文 / 电子工业 / 2005-1 / 25.00元

程序员修炼三部曲丛书包含了四本书,介绍了每个注重实效的程序员和成功团队所必备的一些工具。 注重实效的程序员都会利用反馈来指导开发,并驱动个人的开发流程。编码的时候,最有用的反馈来自于“单元测试”。 为了测试一座桥梁,不会只在晴朗的天气,开一辆汽车从桥中间穿过,就认为已经完成了对桥梁的测试。然而许多程序员却正在使用这种测试方法——把这种一次顺利通过称为“测试”。事实上,注重实效的程序员应......一起来看看 《单元测试之道Java版》 这本书的介绍吧!

CSS 压缩/解压工具
CSS 压缩/解压工具

在线压缩/解压 CSS 代码

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换