JavaScript-小游戏-单词消消乐

需求

生成六个按钮 按钮上的内容随机生成 点到匹配的按钮 那两个按钮就隐藏 (之后会做从单词库随机选取单词的进阶版消消乐)

游戏界面

标签结构(html)

创建一个div类名为game 里面嵌套了六个按钮

html 复制代码
 <div class="game">
    <button></button>
    <button></button>
    <button></button>
    <button></button>
    <button></button>
    <button></button>
  </div>

层叠样式(css)

  • 先用通配符选择器 * 匹配页面中所有的元素清除默认边距和边框
  • 设置button的宽高 写border-radius设计成圆角的按钮 背景色粉色 字体上网找了一个萌一点的字体 字的颜色为白色
css 复制代码
 /* 清除默认样式 */
    * {
      padding: 0;
      margin: 0;
      border: 0;
    }

    button {
      width: 100px;
      height: 100px;
      border-radius: 15%;
      background-color: pink;
      font-size: 15px;
      color: white;
      font-family: Verdana, sans-serif;
    }

获取元素

界面结构写好之后获取div区域 获取按钮用的是querySelectorAll将页面中所有的按钮都获取 这里获得的是NodeList 类数组

document.querySelectorAll('div')得到的数组是div元素

js 复制代码
 const btns = document.querySelectorAll('div')
    console.log(btns);  //NodeList [div.game]

获取元素代码如下

js 复制代码
//获取
    let game = document.querySelector('.game')
    let buttons = document.querySelectorAll('button')

游戏界面如下

数据分析

判断数组

用两个数组a和b分别存放英文和中文 确保这两个数组对应的单词和翻译的索引是一样的 定义的

这两个数组可以简化代码 在判断消除的时候不需要把每个可能都罗列上去 而且可以直接拼接数组 为后面打乱顺序使用

每次刷新按钮上都会打乱顺序生成这些英文和中文 所以另一个数组arr由英文数组a和中文数组b拼接而成

js 复制代码
  //用来对应判断的数组
    let a = ['understand', 'peace', 'forget']
    let b = ['理解', '和平', '忘记']
    //用来打乱的数组
    let arr = a.concat(b)

功能实现

按钮内容随机

随机打乱数组

采用洗牌法 从后往前遍历 当前元素和自己以及前面的元素随机交换 循环的示意图如下

循环过程中 交换范围[0-i]是闭区间的原因
  • 如果是[0-i) 不包含自身来交换 就会打乱平衡

  • [0-i]是闭区间保证了元素在每个位置的概率均等 而且每个元素在某个位置的概率也均等

交换

传统的元素交换方式就是创建一个temp变量 交换本质上不会改变值 只会改变空间的指向 值可以被多个空间指向

以下是数组元素交换的代码举例

js 复制代码
 arr = [0, 1]
    //元素交换
    let t = arr[0]
    arr[0] = arr[1]
    arr[1] = t
    console.log(arr, t);  //[1, 0] 0
随机打乱数组最终代码如下

这里采用的是传统的交换方式

js 复制代码
  //从后往前遍历 拿到的元素和前面的随机交换
    for (let i = arr.length - 1; i > 0; i--) {
      let r = Math.floor(Math.random() * i)
      //元素交换
      let t = arr[i]
      arr[i] = arr[r]
      arr[r] = t
    }

渲染到按钮上

设置buttons数组元素的innerText属性为随机打乱后的数组 渲染到按钮上

js 复制代码
 //随机交换之后渲染到页面
    for (let i = 0; i < arr.length; i++) {
      buttons[i].innerText = arr[i]
    }

最终效果如下 点击刷新按钮之后随机打乱的数组会渲染到按钮上 完成了按钮随机功能

消除功能

数据分析

一开始存在了两个数组里 后面发现存在对象里更合适

对象 是一种无序的数据集合 有属性和方法 这里采用的是属性来存储 属性是以键值对(Key-Value)的形式存在的 每个属性由一个键(key)和一个与之关联的值(value)组成。 数组是特殊的对象 属性名是索引是有序的所以是有序的数据集合

按钮内容存为对象属性的key 用于判断中英文是否匹配,对应的e.target作为value用于匹配成功之后隐藏按钮 都存在对象里 当判断完毕之后清空对象也更方便

点击事件

btns是NodeList类数组 可以用forEach方法遍历数组然后添加点击事件

js 复制代码
    //map给按钮添加点击事件
    btns.forEach((value) => {
      value.addEventListener('click', () => {
        console.log('click');
      })
    }
    )

以下是遍历数组然后添加点击事件效果图示

类数组中没有map方法 如果要使用map方法 需要先 Array.from把btns转换为数组

js 复制代码
 //map给按钮添加点击事件
    Array.from(btns).map((value, index) => {
      value.addEventListener('click', () => {
        console.log('click');
      })
    }
    )
  • 最终利用for循环把所有的按钮都添加点击事件
  • 对象的e.target.innerText属性对应值为e.target 属性名用于判断 属性值用于判断成功之后隐藏对应的按钮
  • 如果judge方法判断匹配 返回true 就把相应的e.target的可见值改为hidden
  • 然后清空对象 便于下次判断
js 复制代码
let obj = {}  //把内容和按钮存在对象里
    for (let i = 0; i < buttons.length; i++) {
      buttons[i].addEventListener('click', (e) => {
        obj[e.target.innerText] = e.target //重复点击也不会有重复的元素
        //点击两个不同的元素才判断
        if (judge()) {
          Object.values(obj)[0].style.visibility = 'hidden'
          Object.values(obj)[1].style.visibility = 'hidden'
          obj = {}
        }
      })
    }

判断方法

  • 遍历a英文数组或者b中文数组 (这里遍历其中任意一个数组就可以 因为这两个数组索引是相对应的 长度也相等) 不需要每种可能都罗列上去
  • 调用Object.keys(obj)获取这个对象中所有的属性名 返回一个数组
  • 如果这个数组中有对应的英文且也有对应的中文 就返回true

这里判断条件改为arr.some((value) => value === a[i] && value===b[i])是不行因为这里的value表示的是当前的元素这个表达式的返回值固定为false当前的元素不可能又等于a[i]又等于b[i] 所以只能分别判断 都为真就返回真

js 复制代码
 //判断方法
    function judge() {
      for (let i = 0; i < a.length; i++) {
        if (Object.keys(obj).some((values) => values === a[i])
          && Object.keys(obj).some((values) => values === b[i])) {
          return true
        }
      }
    }

消除功能最终效果如下

最终代码

js 复制代码
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>单词消消乐</title>
</head>

<body>
  <div class="game">
    <button></button>
    <button></button>
    <button></button>
    <button></button>
    <button></button>
    <button></button>
  </div>
  <style>
    /* 清除默认样式 */
    * {
      padding: 0;
      margin: 0;
      border: 0;
    }

    button {
      width: 100px;
      height: 100px;
      border-radius: 15%;
      background-color: pink;
      font-size: 15px;
      color: white;
      font-family: Verdana, sans-serif;
    }
  </style>

  <script>
    //获取
    let game = document.querySelector('.game')
    let buttons = document.querySelectorAll('button')
    const btns = document.querySelectorAll('div')
    console.log(btns);  //NodeList [div.game]

    //用来对应判断的数组
    let a = ['understand', 'peace', 'forget']
    let b = ['理解', '和平', '忘记']
    //用来打乱的数组
    let arr = a.concat(b)


    //1每次打开页面 按钮位置随机
    //从后往前遍历 拿到的元素和前面的随机交换
    for (let i = arr.length - 1; i > 0; i--) {
      let r = Math.floor(Math.random() * i)
      //元素交换
      let t = arr[i]
      arr[i] = arr[r]
      arr[r] = t
    }

    //随机交换之后渲染到页面
    for (let i = 0; i < arr.length; i++) {
      buttons[i].innerText = arr[i]
    }


    //2 点击对应的两个按钮 就消除
    let obj = {}  //把内容和按钮存在对象里
    for (let i = 0; i < buttons.length; i++) {
      buttons[i].addEventListener('click', (e) => {
        obj[e.target.innerText] = e.target //重复点击也不会有重复的元素
        //点击两个不同的元素才判断
        if (judge()) {
          Object.values(obj)[0].style.visibility = 'hidden'
          Object.values(obj)[1].style.visibility = 'hidden'
          obj = {}
        }
      })
    }

    //判断方法
    function judge() {
      for (let i = 0; i < a.length; i++) {
        if (Object.keys(obj).some((values) => values === a[i])
          && Object.keys(obj).some((values) => values === b[i])) {
          return true
        }
      }
    }

  </script>

</body>

</html>
相关推荐
tyro曹仓舒2 小时前
干了10年前端,才学会使用IntersectionObserver
前端·javascript
mine_mine3 小时前
油猴脚本拦截fetch和xhr请求,实现修改服务端接口功能
javascript
一 乐3 小时前
考公|考务考试|基于SprinBoot+vue的考公在线考试系统(源码+数据库+文档)
前端·javascript·数据库·vue.js·spring boot·课程设计
林太白4 小时前
跟着TRAE SOLO全链路看看项目部署服务器全流程吧
前端·javascript·后端
特级业务专家4 小时前
把 16MB 中文字体压到 400KB:我写了一个 Vite 字体子集插件
javascript·vue.js·vite
先生沉默先4 小时前
NodeJs 学习日志(8):雪花算法生成唯一 ID
javascript·学习·node.js
起这个名字4 小时前
Webpack——插件实现的理解
前端·javascript·node.js
二川bro5 小时前
第51节:Three.js源码解析 - 核心架构设计
开发语言·javascript·ecmascript
djk88886 小时前
多标签页导航后台模板 html+css+js 纯手写 无第三方UI框架 复制粘贴即用
javascript·css·html