服装电子商务网站版式设计,安徽网站建设优化推广,一个彩票网站建设,seo具体seo怎么优化前言#xff1a;我们在学习完了HTML、CSS和JavaScript之后#xff0c;就会想着使用这三个东西去做一些小案例#xff0c;不过又没有什么好的案例让我们去练手#xff0c;本篇文章就提供里一个案例——网页井字棋。 ✨✨✨这里是秋刀鱼不做梦的BLOG ✨✨✨想要了解更多内容可… 前言我们在学习完了HTML、CSS和JavaScript之后就会想着使用这三个东西去做一些小案例不过又没有什么好的案例让我们去练手本篇文章就提供里一个案例——网页井字棋。 ✨✨✨这里是秋刀鱼不做梦的BLOG ✨✨✨想要了解更多内容可以访问我的主页秋刀鱼不做梦-CSDN博客 目录
写在前面 ——该案例的全部代码已经放在文章末尾有兴趣的读者可以到最后将全部代码复制到自己的编译器上运行感受一下井字棋案例的最终效果
——首先先让我们了解一下我们需要了解的前置知识
1.HTML骨架
2.CSS装饰
1. 引入字体和全局样式
2.设置 body 样式
3 设置 .wrapper 样式
4.设置 .current-status 和其中的元素样式 5.设置 board 和 .cell 样式
6.鼠标悬浮时的图片效果
7.设置 game-end-overlay 样式
8 设置 .winning-message 样式
9. 重启按钮样式
3.JavaScript的交互
1. 获取页面元素
2. 初始化游戏状态
3. 所有获胜组合
4. 设置鼠标悬停时的样式
5. 在格子上放置图片
6. 切换回合
7. 更新当前状态
8. 检查是否获胜
9. 判断是否平局
10. 开始游戏
11. 结束游戏
12. 处理格子点击事件
13. 重置游戏
14. 启动游戏
——所有代码 写在前面 ——该案例的全部代码已经放在文章末尾有兴趣的读者可以到最后将全部代码复制到自己的编译器上运行感受一下井字棋案例的最终效果
——首先先让我们了解一下我们需要了解的前置知识 HTML内容 HTML基础标签的使用 CSS内容 通用样式重置 (* { margin: 0; padding: 0; box-sizing: inherit; }) Flexbox 布局 (display: flex, justify-content, align-items) CSS Grid 布局 (grid-template-columns, grid-template-rows, grid-gap) 背景和图像处理 (background-size, background-image) 伪元素 (::before) 伪类:hover 动画与过渡效果 (transition, transform) 使用 CSS 类控制显示与隐藏 JavaScript内容 DOM 操作 (document.getElementById(), document.querySelector()) 类操作 (element.classList.add(), element.classList.remove()) 事件监听与处理 (addEventListener(), removeEventListener()) 回调函数与事件处理 轮换玩家逻辑 (unicornTurn 变量) 胜利判断与平局判断 (winningCombinations, checkWin(), isDraw()) 函数设计与重用性 函数封装与模块化设计 重用性和功能拆分如 startGame(), placeBeastImg() 条件判断与数组方法 Array.prototype.some() 和 Array.prototype.every() ——了解完了实现这个小案例所需掌握的基本知识之后让我们看一下该案例的最终结果 ——案例中所需的资源读者可以右键进行下载 ——那么接下来就让我们正式进行案例讲解吧 1.HTML骨架 ——首先先让我们搭建一下HTML骨架由于内容比较简单所以我们就不进行详细讲解了以下为HTML代码
!DOCTYPE html
html langenheadmeta charsetUTF-8meta http-equivX-UA-Compatible contentIEedgemeta nameviewport contentwidthdevice-width, initial-scale1.0title秋刀鱼不做梦/title!-- 引入外部样式表 --link relstylesheet href./index.css!-- 延迟加载外部 JavaScript 文件 --script defer src./index.js/script
/headbody!-- 游戏主要容器 --div classwrapper!-- 当前状态显示区域 --div classcurrent-status idcurrentStatus!-- 当前游戏角色的图片 --img src./1.gif idcurrentBeastImg alt!-- 当前轮到哪方玩家 --pnbsp; s turn/p/div!-- 游戏棋盘 --div classboard idboard!-- 游戏棋盘的每个格子标记为 data-cell --div classcell data-cell/divdiv classcell data-cell/divdiv classcell data-cell/divdiv classcell data-cell/divdiv classcell data-cell/divdiv classcell data-cell/divdiv classcell data-cell/divdiv classcell data-cell/divdiv classcell data-cell/div/div!-- 游戏结束时显示的覆盖层 --div classgame-end-overlay idgameEndOverlay!-- 游戏胜利信息显示区域 --div classwinning-message data-winning-messagep/p/div!-- 重启游戏的按钮容器 --div classbtn-container!-- 重启按钮 --button classreset-button idresetButtonplay again/button/div/div/div
/body/html在上面的代码中我们对代码进行了讲解读者可以根据注释对代码进行理解
让我们看一下上述代码的最终结果 嗯......看起来不尽人意其实有很多的结构由于其内部没有内容所以其高度为0所以看起来和没有一样不过接下来就让我们开始对其进行修饰吧 2.CSS装饰 ——在编写完了HTML代码之后在让我们为其进行乔装打扮一下吧
1. 引入字体和全局样式
/* 引入自定义字体 Bungee Inline */
import url(https://fonts.googleapis.com/css2?familyBungeeInlinedisplayswap);/* 全局样式 */
* {padding: 0; /* 清除所有元素的内边距 */margin: 0; /* 清除所有元素的外边距 */box-sizing: inherit; /* 继承父元素的盒子模型 */
}这部分的代码做了两件事首先它引入了一种叫 Bungee Inline 的自定义字体这样我们就可以在页面中使用这个特别的字体来呈现文本了接着* 选择器把所有元素的默认 padding内边距和 margin外边距清除了因为不同浏览器可能会有不同的默认值这样做是为了让布局更加一致。 另外我们使用 box-sizing: inherit; 确保所有元素的盒模型计算方式一致避免意外的布局问题。 2.设置 body 样式
body {margin: 0;padding: 0;display: flex; /* 使用 Flexbox 布局 */justify-content: center; /* 内容水平居中 */align-items: center; /* 内容垂直居中 */height: 100vh; /* 高度为视口的 100% */text-align: center; /* 文字居中 */font-family: Bungee Inline, cursive; /* 设置字体 */color: #f5f5f5; /* 文字颜色 */overflow: hidden; /* 防止页面出现滚动条 */background-image: linear-gradient(to top, #a8edea 0%, #ffc7d9 100%); /* 背景渐变色 */
}这里我们设置了页面的基础样式display: flex; 和 justify-content: center;、align-items: center; 这三行代码让页面的内容居中显示既水平居中又垂直居中然后height: 100vh; 让页面高度占满整个屏幕这样就不会出现页面高度不够的情况背景设置了渐变色从蓝色渐变到粉色overflow: hidden; 让页面没有滚动条。 3 设置 .wrapper 样式
.wrapper {background-color: #55acee53; /* 背景颜色带透明度 */padding: 50px; /* 内边距 */
}.wrapper 类是用来包裹整个游戏内容的容器。在这里我们给它设置了一个带透明度的蓝色背景通过 padding: 50px; 我们给容器添加了 50px 的内边距避免内容紧贴容器的边缘。 4.设置 .current-status 和其中的元素样式
.current-status {display: flex; /* 使用 Flexbox 布局 */justify-content: center; /* 内容水平居中 */align-items: center; /* 内容垂直居中 */margin-bottom: 25px; /* 底部间距 */
}.current-status p {margin: 0 5px 0 0; /* 给 p 元素的右侧添加间距 */font-size: 24px; /* 设置字体大小 */
}.current-status img {width: auto; /* 自动设置图片宽度 */height: 32px; /* 设置图片高度 */
}这个部分是用来显示当前游戏状态的比如谁的回合.current-status 使用了 Flexbox 布局把文字和图片都居中对齐然后通过 margin-bottom: 25px; 我们为这个部分和下面的内容增加了一点间距p 标签控制了文字的大小和间距而 img 标签则设置了图片的高度为 32px确保它在界面上看起来合适。 5.设置 board 和 .cell 样式
.board {display: grid; /* 使用 CSS Grid 布局 */grid-template-columns: repeat(3, minmax(90px, 1fr)); /* 设置 3 列每列最小宽度为 90px */grid-template-rows: repeat(3, minmax(90px, 1fr)); /* 设置 3 行每行最小高度为 90px */grid-gap: 12px; /* 设置单元格之间的间距 */width: 100%; /* 宽度为 100% */height: 100%; /* 高度为 100% */max-width: 495px; /* 最大宽度为 495px */margin: 0 auto 15px; /* 居中对齐并设置底部间距 */
}.cell {cursor: pointer; /* 鼠标悬浮时显示手形光标 */position: relative; /* 使单元格可相对定位 */background-color: #f5f5f5; /* 单元格背景色 */width: 90px; /* 宽度为 90px */height: 90px; /* 高度为 90px */opacity: 0.5; /* 初始透明度为 0.5 */transition: opacity 0.2s ease-in-out; /* 设置透明度变化的过渡效果 */
}.cell:hover {opacity: 1; /* 鼠标悬浮时完全不透明 */
}在这里我们首先为 .board 设置了一个 3x3 的网格布局这样游戏棋盘就能整齐地排列起来然后通过 grid-template-columns 和 grid-template-rows 我们定义了每一列和每一行的最小尺寸grid-gap: 12px; 则让每个格子之间有了 12px 的间隙使得棋盘看起来不那么拥挤。 每个单元格 .cell 都有固定的宽度和高度并且设置了初始透明度为 0.5cursor: pointer; 让鼠标悬浮时变成手形表示用户可以点击当鼠标悬停时透明度会变为 1单元格变得完全不透明从而提供交互反馈。 6.鼠标悬浮时的图片效果
/* 鼠标悬浮时显示图片 */
.board.unicorn .cell:not(.dragon):not(.unicorn):hover::before,
.board.dragon .cell:not(.dragon):not(.unicorn):hover::before {content: ;width: 70%;height: 70%;display: block;position: absolute;background-repeat: no-repeat;top: 50%;left: 50%;transform: translate3d(-50%, -50%, 0);background-size: contain;opacity: 50%;
}.board.unicorn .cell:not(.dragon):hover::before {background-image: url(./1.gif); /* 显示独角兽图片 */
}.board.dragon .cell:not(.unicorn):hover::before {background-image: url(./2.gif); /* 显示龙的图片 */
}这一段是让棋盘格子在鼠标悬停时显示图片效果根据不同的游戏状态我们通过 ::before 在单元格上显示一个小的动画图片当玩家将鼠标悬停在一个空白格子上时会看到一个对应的动画图像显示出来。 7.设置 game-end-overlay 样式
.game-end-overlay {display: none; /* 默认隐藏 */position: fixed; /* 固定定位 */top: 0;left: 0;right: 0;bottom: 0;background-color: #0d1021; /* 半透明背景 */
}.game-end-overlay.show {display: flex; /* 游戏结束时显示 */flex-direction: column;justify-content: center;align-items: center;
}这部分控制了游戏结束时弹窗的显示.game-end-overlay 默认是隐藏的只有游戏结束时才会显示当 show 类被添加时弹窗会用 flex 布局显示出来并且通过 justify-content 和 align-items 保证内容居中显示。 8 设置 .winning-message 样式
.winning-message {margin: -50px 0 20px; /* 设置外边距 */
}.winning-message img {width: 100px; /* 设置图片宽度 */
}.winning-message p {font-size: 48px; /* 设置字体大小 */margin: 0; /* 去除外边距 */
}这里的 .winning-message 是用来显示获胜信息的部分我们给它设置了一些外边距确保它和其他内容不会紧挨在一起图片的宽度被固定为 100px文字的大小则是 48px。 9. 重启按钮样式
.reset-button {color: #f5f5f5;font-family: Bungee Inline, cursive;font-size: 30px;white-space: nowrap;border: none;padding: 10px 20px;background-color: #a186be;box-shadow: 5px 5px 0 #55acee;cursor: pointer;transition: transform 0.1s ease-in-out;position: relative;
}.reset-button:hover {transform: scale(1.2); /* 鼠标悬浮时按钮变大 */
}.reset-button:active {top: 6px;left: 6px;box-shadow: none;background-color: #9475b5;
}这部分代码定义了“重新开始”按钮的样式在 hover 状态下按钮会稍微放大而在 active 状态下即按钮被点击时按钮会下沉并去除阴影背景色也会变化。
让我们看一下上述代码的最终结果 嗯……好看很多了至此我们就了解了井字棋小游戏的CSS代码如何编写了 3.JavaScript的交互 在编写完了HTML骨架和CSS样式之后最后在让我们为其添加一些交互效果来完成双人井字棋。
1. 获取页面元素
// 获取页面元素
const board document.getElementById(board);
const cells document.querySelectorAll([data-cell]);
const currentStatus document.getElementById(currentStatus);
const resetButton document.getElementById(resetButton);
const gameEndOverlay document.getElementById(gameEndOverlay);
const currentBeastStatusImg document.getElementById(currentBeastImg);
const winningMessage document.querySelector([data-winning-message]);
const winningMessageText document.querySelector([data-winning-message] p);
const winningMessageImg document.createElement(img);——这段代码是用来获取 HTML 中的各种元素主要是通过它们来操作游戏的显示和互动。例如 board 是游戏棋盘的容器通过它我们可以控制整个棋盘的样式和逻辑。 cells 用来获取所有的格子格子上有 data-cell 属性每个格子都是用户点击的地方。 currentStatus 是用来显示当前回合玩家的地方告诉你是哪一方的回合。 resetButton 是“重新开始”按钮点击后会重新初始化游戏。 gameEndOverlay 是一个覆盖层当游戏结束时会显示在屏幕上告诉玩家结果。 currentBeastStatusImg 显示的是当前回合玩家的图标。 winningMessage 负责显示游戏的获胜消息或平局消息。 winningMessageText 和 winningMessageImg 主要用来动态更新显示的信息和获胜的图标。 2. 初始化游戏状态
// 初始化游戏状态
let gameIsLive true;
let unicornTurn true;
let winner null; // 没有赢家
在这部分我们设置了一些变量来控制游戏的状态 gameIsLive 是一个标志表示游戏是否还在进行。如果为 false游戏就结束了。 unicornTurn 表示当前回合是谁。 winner 用来存储游戏的获胜者开始时没有赢家所以是 null。 3. 所有获胜组合
// 所有获胜组合
const winningCombinations [[0, 1, 2],[3, 4, 5],[6, 7, 8],[0, 3, 6],[1, 4, 7],[2, 5, 8],[0, 4, 8],[2, 4, 6]
];这个数组 winningCombinations 包含了所有可能的获胜组合。它是一个二维数组每个子数组里列出的是三格连成一条线的格子的索引。 例如[0, 1, 2] 就表示第一行的三个格子。 游戏的胜负就是看这些组合中的每一行格子是否全部被同一个玩家占领。 4. 设置鼠标悬停时的样式
// 设置鼠标悬停时的样式
const setBoardHoverClass () {board.classList.remove(unicorn);board.classList.remove(dragon);if (unicornTurn) {board.classList.add(unicorn);} else {board.classList.add(dragon);}
}这个函数是用来设置鼠标悬停在棋盘格子上时的样式的。具体来说 每次回合切换时都会根据是哪个玩家的回合来修改棋盘的样式。 5. 在格子上放置图片
// 在格子上放置图片
const placeBeastImg (cell, currentBeast) {cell.classList.add(currentBeast);
}这个函数的作用是将图标放到点击的格子里。它的逻辑很简单 cell 是被点击的格子。 currentBeast 是当前玩家的标识。 我们通过 classList.add 把对应的玩家的类名添加到格子中这样就能在格子中显示相应的图标。 6. 切换回合
// 切换回合
const swapTurns () {unicornTurn !unicornTurn; // 切换回合
} ——当玩家点击了一个格子后我们需要切换到另一个玩家的回合。这个函数通过反转 unicornTurn 来实现回合切换 7. 更新当前状态
// 更新当前状态
const updateCurrentStatus () {if (unicornTurn) {currentBeastStatusImg.src ./1.gif;currentBeastStatusImg.alt unicorn;} else {currentBeastStatusImg.src ./2.gif;currentBeastStatusImg.alt dragon;}
}——这部分代码的作用是更新页面上显示的当前回合玩家的图标 8. 检查是否获胜
// 检查是否获胜
const checkWin (currentBeast) {return winningCombinations.some(combination {return combination.every(i {return cells[i].classList.contains(currentBeast); // 判断当前组合的所有格子是否都包含当前玩家的类})});
}这里的 checkWin 函数是用来检查当前玩家是否获胜的 winningCombinations 包含了所有可能的获胜组合。 通过 some 和 every 方法我们遍历这些组合看看每一组的格子是否都被当前玩家占领。如果某一组格子都被占领了就说明当前玩家获胜。 9. 判断是否平局
// 判断是否平局
const isDraw () {return [...cells].every(cell {return cell.classList.contains(unicorn) || cell.classList.contains(dragon);})
}isDraw 函数用来检查是否发生了平局 如果所有的格子都被填满了并且没有赢家游戏就会是平局。 10. 开始游戏
// 开始游戏
const startGame () {cells.forEach(cell {winningMessageImg.remove(); // 移除任何先前的胜利图片cell.classList.remove(unicorn, dragon); // 移除所有格子的类cell.removeEventListener(click, handleCellClick); // 移除之前的点击事件cell.addEventListener(click, handleCellClick, { once: true }); // 给每个格子添加点击事件});setBoardHoverClass(); // 更新棋盘的悬停样式gameEndOverlay.classList.remove(show); // 隐藏游戏结束的遮罩层
}
这部分是用来初始化或者重置游戏的 每个格子都被清空移除所有的 unicorn 和 dragon 类。 同时移除先前的点击事件防止重复绑定然后重新给每个格子绑定点击事件。 更新棋盘的悬浮样式确保玩家能看到当前回合的样式。 如果游戏已经结束隐藏游戏结束的遮罩层。 11. 结束游戏
// 结束游戏
const endGame (draw) {if (draw) {winningMessageText.innerText draw!; // 平局时的消息} else {winningMessageImg.src unicornTurn ? ./1.gif : ./2.gif; // 根据回合显示获胜者的图片winningMessageImg.alt unicornTurn ? unicorn : dragon;winningMessage.insertBefore(winningMessageImg, winningMessageText); // 显示获胜者的图片winningMessageText.innerText wins!!!; // 显示获胜者的文字}gameEndOverlay.classList.add(show); // 显示游戏结束的遮罩层
}这段代码在游戏结束时调用 如果是平局显示 draw!。 如果有赢家显示获胜玩家的图像和“wins!!!”。 最后显示游戏结束的覆盖层表示游戏已结束。 12. 处理格子点击事件
// 处理格子点击事件
const handleCellClick (e) {const cell e.target;const currentBeast unicornTurn ? unicorn : dragon; // 获取当前玩家placeBeastImg(cell, currentBeast); // 在格子中放置当前玩家的标识if (checkWin(currentBeast)) {endGame(false); // 如果当前玩家获胜结束游戏} else if (isDraw()) {endGame(true); // 如果是平局结束游戏} else {swapTurns(); // 切换回合updateCurrentStatus(); // 更新当前状态setBoardHoverClass(); // 更新棋盘的悬停样式}
}这段代码处理每次玩家点击格子时的逻辑 获取当前玩家的标识。 在点击的格子中放置当前玩家的图标。 检查是否有玩家获胜或是否是平局。如果有获胜者或平局调用 endGame 结束游戏。 如果游戏没有结束切换到下一个回合更新游戏状态并重新设置棋盘的悬浮效果。 13. 重置游戏
// 重置游戏
resetButton.addEventListener(click, startGame);——这个事件监听器让玩家可以通过点击“重新开始”按钮来重置游戏游戏会回到初始状态。 14. 启动游戏
// 开始游戏
startGame();——最后我们调用 startGame 来初始化并启动游戏。这是游戏启动时最先调用的函数确保游戏界面和逻辑都设置好。 至此我们就讲解完了JavaScript与用户交互方面的代码了
让我们看一下最终的效果 ——所有代码
!DOCTYPE html
html langenheadmeta charsetUTF-8meta http-equivX-UA-Compatible contentIEedgemeta nameviewport contentwidthdevice-width, initial-scale1.0title秋刀鱼不做梦/titlestyleimport url(https://fonts.googleapis.com/css2?familyBungeeInlinedisplayswap);* {padding: 0;margin: 0;box-sizing: inherit;}body {margin: 0;padding: 0;display: flex;justify-content: center;align-items: center;height: 100vh;text-align: center;font-family: Bungee Inline, cursive;color: #f5f5f5;overflow: hidden;background-image: linear-gradient(to top, #a8edea 0%, #ffc7d9 100%);}.wrapper {background-color: #55acee53;padding: 50px;}.current-status {display: flex;justify-content: center;align-items: center;margin-bottom: 25px;}.current-status p {margin: 0 5px 0 0;font-size: 24px;}.current-status img {width: auto;height: 32px;}.board {display: grid;grid-template-columns: repeat(3, minmax(90px, 1fr));grid-template-rows: repeat(3, minmax(90px, 1fr));grid-gap: 12px;width: 100%;height: 100%;max-width: 495px;margin: 0 auto 15px;}/* 鼠标悬浮的时候显示图片 */.board.unicorn .cell:not(.dragon):not(.unicorn):hover::before,.board.dragon .cell:not(.dragon):not(.unicorn):hover::before {content: ;width: 70%;height: 70%;display: block;position: absolute;background-repeat: no-repeat;top: 50%;left: 50%;transform: translate3d(-50%, -50%, 0);background-size: contain;opacity: 50%;}.board.unicorn .cell:not(.dragon):hover::before {background-image: url(./1.gif);}.board.dragon .cell:not(.unicorn):hover::before {background-image: url(./2.gif);}.cell {cursor: pointer;position: relative;background-color: #f5f5f5;width: 90px;height: 90px;opacity: 0.5;transition: opacity 0.2s ease-in-out;}.cell:hover {opacity: 1;}.cell.dragon,.cell.unicorn {opacity: 1;position: relative;cursor: not-allowed;}.cell.dragon::before,.cell.unicorn::before {content: ;width: 70%;height: 70%;display: block;position: absolute;background-repeat: no-repeat;top: 50%;left: 50%;transform: translate3d(-50%, -50%, 0);background-size: contain;}.cell.dragon::before {background-image: url(./2.gif);}.cell.unicorn::before {background-image: url(./1.gif);}.game-end-overlay {display: none;position: fixed;top: 0;left: 0;right: 0;bottom: 0;background-color: #0d1021;}.game-end-overlay.show {display: flex;flex-direction: column;justify-content: center;align-items: center;}.winning-message {margin: -50px 0 20px;}.winning-message img {width: 100px;}.winning-message p {font-size: 48px;margin: 0;}.btn-container {position: relative;}.reset-button {color: #f5f5f5;font-family: Bungee Inline, cursive;font-size: 30px;white-space: nowrap;border: none;padding: 10px 20px;background-color: #a186be;box-shadow: 5px 5px 0 #55acee;cursor: pointer;transition: transform 0.1s ease-in-out;position: relative;}.reset-button:hover {transform: scale(1.2);}.reset-button:active {top: 6px;left: 6px;box-shadow: none;background-color: #9475b5;}/style
/headbodydiv classwrapperdiv classcurrent-status idcurrentStatusimg src./1.gif idcurrentBeastImg altpnbsp; s turn/p/divdiv classboard idboarddiv classcell data-cell/divdiv classcell data-cell/divdiv classcell data-cell/divdiv classcell data-cell/divdiv classcell data-cell/divdiv classcell data-cell/divdiv classcell data-cell/divdiv classcell data-cell/divdiv classcell data-cell/div/divdiv classgame-end-overlay idgameEndOverlaydiv classwinning-message data-winning-messagep/p/divdiv classbtn-containerbutton classreset-button idresetButtonplay again/button/div/div/divscript// 获取页面元素const board document.getElementById(board);const cells document.querySelectorAll([data-cell]);const currentStatus document.getElementById(currentStatus);const resetButton document.getElementById(resetButton);const gameEndOverlay document.getElementById(gameEndOverlay);const currentBeastStatusImg document.getElementById(currentBeastImg);const winningMessage document.querySelector([data-winning-message]);const winningMessageText document.querySelector([data-winning-message] p);const winningMessageImg document.createElement(img);// 初始化游戏状态let gameIsLive true;let unicornTurn true;let winner null;// 所有获胜组合const winningCombinations [[0, 1, 2],[3, 4, 5],[6, 7, 8],[0, 3, 6],[1, 4, 7],[2, 5, 8],[0, 4, 8],[2, 4, 6]];// 设置鼠标悬停时的样式const setBoardHoverClass () {board.classList.remove(unicorn);board.classList.remove(dragon);if (unicornTurn) {board.classList.add(unicorn);} else {board.classList.add(dragon);}}// 在格子上放置图片const placeBeastImg (cell, currentBeast) {cell.classList.add(currentBeast);}// 切换回合const swapTurns () {unicornTurn !unicornTurn;}// 更新当前状态const updateCurrentStatus () {if (unicornTurn) {currentBeastStatusImg.src ./1.gif;currentBeastStatusImg.alt unicorn;} else {currentBeastStatusImg.src ./2.gif;currentBeastStatusImg.alt dragon;}}// 检查是否获胜const checkWin (currentBeast) {return winningCombinations.some(combination {return combination.every(i {return cells[i].classList.contains(currentBeast);})});}// 判断是否平局const isDraw () {return [...cells].every(cell {return cell.classList.contains(unicorn) || cell.classList.contains(dragon);})}// 开始游戏const startGame () {cells.forEach(cell {winningMessageImg.remove();cell.classList.remove(unicorn);cell.classList.remove(dragon);cell.removeEventListener(click, handleCellClick);cell.addEventListener(click, handleCellClick, { once: true });});setBoardHoverClass();gameEndOverlay.classList.remove(show);}// 结束游戏const endGame (draw) {if (draw) {winningMessageText.innerText draw!;} else {winningMessageImg.src unicornTurn ? ./1.gif : ./2.gif;winningMessageImg.alt unicornTurn ? unicorn : dragon;winningMessage.insertBefore(winningMessageImg, winningMessageText);winningMessageText.innerText wins!!!}gameEndOverlay.classList.add(show);}// 处理格子点击事件const handleCellClick (e) {const cell e.target;const currentBeast unicornTurn ? unicorn : dragon;placeBeastImg(cell, currentBeast);if (checkWin(currentBeast)) {endGame(false);} else if (isDraw()) {endGame(true);} else {swapTurns();updateCurrentStatus();setBoardHoverClass();}}// 重置游戏resetButton.addEventListener(click, startGame);// 开始游戏startGame();/script
/body/html 以上就是本篇文章全部内容了