内容简介:前段时间换了家外企工作, 空闲时间比较多。虽然我是做Java后端的,但是老外喜欢搞敏捷开发和全栈,所以也要写前端,既然是老外,那肯定是喜欢用React的,然而我之前从来没写过React,只能从基础一步一步来了。井字游戏是React官方的入门实战教程的案例来的,在这里。
前段时间换了家外企工作, 空闲时间比较多。
虽然我是做 Java 后端的,但是老外喜欢搞敏捷开发和全栈,所以也要写前端,既然是老外,那肯定是喜欢用React的,然而我之前从来没写过React,只能从基础一步一步来了。
井字游戏
井字游戏是React官方的入门实战教程的案例来的,在这里。
这个游戏的规则是这样的:
- 一共9个格子的棋盘, 共2种棋子,分别是X和O
- 每次,一个玩家将棋子下到一个格子上
- 如果有3个相同棋子在横/竖/对角线上相连,那就赢了,否则就为和局
最后的效果是这样的:
实现
我的实现就是完全跟着官方教程来的,最后挑了一些有趣的课后作业完成,分别新增了下面的功能:
- 点击历史列表某一项时,这一项的文字加粗
- 将原来硬编码写的九宫格改成用循环
- 如果是平局,在界面上显示出来
都是比较简单的功能,我还想到了一个功能,就是给一个回放的按钮,点击可以回放整个游戏过程。
所以,增加了上面的4个功能的实现,最终的效果变成:
点击历史列表某一项时,这一项的文字加粗
在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)
}
复制代码
整个实现就是这样的了! 忘了要把源码附上,在 这里
本文首发于我的博客。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- Go语言从入门到精通-08| Web服务完善之路径参数
- Go语言从入门到精通-07| Web服务完善之图片文件支持
- Go语言从入门到精通-06| Web服务完善之HTML文件支持
- 自己动手修改完善yilia主题
- 自己动手修改完善yilia主题(下)
- 更完善的 Docker + Traefik 使用方案
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
应用密码学:协议、算法与C源程序(原书第2版)
(美)Bruce Schneier / 吴世忠、祝世雄、张文政 等 / 机械工业出版社 / 2014-1 / 79.00
......我所读过的关于密码学最好的书......该书是美国国家安全局最不愿意见到出版的书...... —— 《Wired》 ......不朽的......令人着迷的......计算机程序员必读的密码学上决定性的著作...... —— 《Dr.Dobb's Journal》 ......该领域勿庸置疑的一本权威之作。 —— 《PC Magazine》 ..........一起来看看 《应用密码学:协议、算法与C源程序(原书第2版)》 这本书的介绍吧!