携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第10天,点击查看活动详情
单元格点击
效果:点击棋盘的任意单元格,单元格显示×(默认)
思路:
1.获取到所有的单元格列表
2.遍历单元格列表,给每一个单元格添加点击事件
3.给当前被点击的单元格添加类名 x
引入js
1、新建 index.ts 文件,同时在终端中执行 tsc --watch index.ts
来生成 js 文件
2、demo.html 中在 body 结束标签前,引入 index.js
<script src="./index.js"></script>
复制代码
编写代码
/*
单元格点击
1.获取到所有的单元格列表
2.遍历单元格列表,给每一个单元格添加点击事件
3.给当前被点击的单元格添加类名 x
*/
let cells = document.querySelectorAll('.cell')
cells.forEach(function (item, index) {
let cell = item as HTMLDivElement;
cell.addEventListener('click',function (event) {
let target = event.target as HTMLDivElement
target.classList.add('x')
})
})
复制代码
优化
1、防止单元格重复点击,在添加事件时,使用 once 属性,让单元格只能被点击一次
2、使用函数声明形式的事件处理程序(代码多了后,代码结构会更清晰)
/*
单元格点击
1.获取到所有的单元格列表
2.遍历单元格列表,给每一个单元格添加点击事件
3.给当前被点击的单元格添加类名 x
*/
let cells = document.querySelectorAll('.cell')
cells.forEach(function (item, index) {
let cell = item as HTMLDivElement;
cell.addEventListener('click', clickCell, {once: true})
})
//棋盘中单元格的click事件处理程序
function clickCell(event) {
let target = event.target as HTMLDivElement
target.classList.add('x')
}
复制代码
切换玩家
效果:玩家(x)和玩家(o)轮流交替下棋
思路:
1.创建一个存储当前玩家的变量(currentPlayer),默认值为:x
2.将添加给单元格时写死的类名x,替换为变量(currentPlayer)的值
3.切换到另一个玩家:在添加类名(下棋完成一步)后,根据当前玩家,得到另外一个玩家
4.处理下一步提示:移除游戏面板中的x和o类名,添加下一个玩家对应的类名
let cells = document.querySelectorAll('.cell')
let currentPlayer = 'x'
let gameBoard = document.querySelector('#bord')
cells.forEach(function (item, index) {
let cell = item as HTMLDivElement;
cell.addEventListener('click', clickCell, {once: true})
})
//棋盘中单元格的click事件处理程序
function clickCell(event) {
let target = event.target as HTMLDivElement
target.classList.add(currentPlayer)
currentPlayer = currentPlayer === 'x'?'o':'x'
gameBoard.classList.remove('x','o')
gameBoard.classList.add(currentPlayer)
}
复制代码
使用枚举
使用变量(currentPlayer)处理当前玩家,存在的问题:
1、变量的类型是 string,它的值可以是任意字符串
如果不小心写错了(o→0),代码不会报错,但功能就无法实现了,并且很难找错。也就是 string 类型的变量,取值太宽泛,无法很好的限制值为 x 和 o
enum Player {
X = 'x',
O = 'o'
}
let cells = document.querySelectorAll('.cell')
let currentPlayer = Player.X
let gameBoard = document.querySelector('#bord')
console.log(cells)
cells.forEach(function (item, index) {
let cell = item as HTMLDivElement;
cell.addEventListener('click', clickCell, {once: true})
})
//棋盘中单元格的click事件处理程序
function clickCell(event) {
let target = event.target as HTMLDivElement
target.classList.add(currentPlayer)
currentPlayer = currentPlayer === Player.X ? Player.O : Player.X
gameBoard.classList.remove(Player.X, Player.O)
gameBoard.classList.add(currentPlayer)
}
复制代码
游戏判赢思路
判赢的思路:
判断棋盘中,横、竖、斜(对角线)是否存在三个相同的 x 或 o,只要有一个满足条件,就说明 x 或 o 获胜了 如果所有单元格都有内容,但没有获胜的情况,就说明是平局
我们打印页面上的单元格,发现每个单元格都有索引
console.log(cells)
复制代码
这样我们可以使用单元格索引,来表示每种获胜情况(使用数组来存储,比如:[0,1,2])
所有获胜情况:
横:[0,1,2]、[3,4,5]、[6,7,8]
竖:[0,3,6]、[1,4,7]、[2,5,8]
斜:[0,4,8]、[2,4,6]
所以每次判赢的时候,都需要判断这8种情况。所以我们可以使用一个“大”数组(外层),来存储这 8 种情况(因为每次判赢都要判断所有情况)
判断过程: 遍历这个大数组,分别判断每一种情况对应的3个单元格元素,是否都是相同的 x 或 o 类名,只要有一种情况满足,就说明获胜了
单元格元素列表说明:
单元格元素列表(cells),实际上是一个伪数组(伪数组的特征:具有长度(length)属性和索引),为什么它不是一个真正的数组呢,我们把鼠标放到 cells 上可以看到类型是 NodeListOf<Element>
伪数组的操作:
1、通过索引获取元素
console. log(cells[0])
console. log (cells[1])
复制代码
2、使用for循环遍历(推荐使用 forEach 方法)
for ( let i = 0; i < cells.length; i++){
console.log(cells[i])
)
复制代码