需求
生成六个按钮 按钮上的内容随机生成 点到匹配的按钮 那两个按钮就隐藏 (之后会做从单词库随机选取单词的进阶版消消乐)
游戏界面
标签结构(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>