JS实现井字棋(功能实现-上)

·  阅读 372

携手创作,共同成长!这是我参与「掘金日新计划 · 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])
)
复制代码
分类:
前端
标签:
分类:
前端
标签:
收藏成功!
已添加到「」, 点击更改