1. 目标:完成扫雷操作
2. 效果:
3. 思路:
(1) html创建基本框架、CSS为其添加样式
(2) 扫雷盒子中的方块由js创建
(3) js完成扫雷基本操作
4. 代码实现
- html
<div class="box">
<div id="mine">
</div>
<div class="footer">
<div id="time">
<div class="circle">
<img src="jpg/time.svg" alt="">
</div>
<div class="rect" id="time_box"></div>
</div>
<div id="remain">
<div class="rect" id="boomnum">2</div>
<div class="circle">
<img src="jpg/peng.svg" alt="">
</div>
</div>
</div>
</div>
- css
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
width: 100vw;
height: 100vh;
background: url('http://43.138.24.196/old/mine2/imgs/bg.jpg');
background-size: 100%;
background-repeat: no-repeat;
}
.box {
width: 700px;
height: 500px;
background-color: rgb(255, 255, 255, 0.6);
box-shadow: 0 0 10px rgb(0, 0, 0, 0.6);
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
margin: auto;
display: flex;
flex-direction: column;
}
#mine {
width: 600px;
cursor: pointer;
display: flex;
flex-wrap: wrap;
align-content: center;
justify-content: center;
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
margin: auto;
}
.footer {
width: 100%;
position: absolute;
bottom: 20px;
display: flex;
align-items: center;
justify-content: space-around;
}
#time,
#remain {
width: 150px;
height: 25px;
display: flex;
align-items: center;
justify-content: space-evenly;
}
.circle {
width: 30px;
height: 100%;
border-radius: 50%;
overflow: hidden;
}
.circle img {
width: 100%;
height: 100%;
}
.rect {
width: 80px;
height: 100%;
margin: 0 10px;
font-size: 14px;
color: #13651b;
border-radius: 10%;
display: flex;
align-items: center;
justify-content: center;
box-shadow: 5px 5px 25px 2px #2aa913;
}
.item {
width: 20px;
height: 20px;
background: url('http://43.138.24.196/old/mine2/imgs/kuai.png');
background-repeat: no-repeat;
background-size: 110%;
border: 1px solid black;
font-size: 15px;
font-weight: bold;
text-align: center;
line-height: 20px;
}
.item:hover {
background: url('http://43.138.24.196/old/mine2/imgs/kuai_hover.png');
background-size: 120%;
}
- JS
//声明变量
var boomsum = 0; //雷总数
var time = 0; //所用时间
- 循环给id为mine的盒子添加子元素(行16个列30个)
- 通过创建document.createElement('')产生div,并为其加item类,和id,便于后续函数操作
- 利用Math.random()产生随机数,随机为div添加boom类
- appendChild()函数为id为mine的盒子追加div元素
- 将生成的boom类个数作为炸弹总数显示
- 代码中函数使用
- document.createElement('')
- 在html中创建一个元素
- 传入html的标签名
- 返回值是 Element
- Math.random()
- 产生[0,1)的随机数
- 可以通过调整 Math.random() > 0.8数值去调整炸弹数量
- e.classList.add()
- 为元素添加类名
- e.appendChild(el)
- 向e追加子元素e
- 如果el已在html中存在,调用此函数是将el移动到e最后一个子元素
for (var i = 0; i < 16; i++) { for (var j = 0; j < 30; j++) { var div = document.createElement('div'); div.classList.add('item'); div.id = '_' + i + '_' + j; //随机加炸弹 if (Math.random() > 0.8) { div.classList.add('boom'); boomsum++; } mine.appendChild(div); } boomnum.textContent = boomsum; }
- 页面炸弹总数和时间显示
- setInterval() 显示当前时间,函数会每秒执行一次函数,类似手表
//返回炸弹总数 function display_boomsum() { boomnum.textContent = boomsum; return boomsum; } //显示时间 var display_timesum = function () { time++; timebox.textContent = time; } var timesum = setInterval(display_timesum, 1000);
- 处理鼠标交互事件
- 元素的buttons属性使用前测试一下浏览器,左右键的值
- 1为左,2为右
- flag为右键点击出现的旗帜、q为疑问标识
- open 打开盒子函数
- check()检查此时标识到的旗帜是否都为boom
- 代码中的函数
- e.classList.contains('')
- 检查e的类中有无括号中的
- 返回值是布尔值
- e.classList.remove('')
- 移除e中括号中的类
- 返回值是布尔值
- clearInterval()
- 可取消由 setInterval() 函数设定的定时执行操作
- clearInterval() 方法的参数必须是由 setInterval() 返回的 ID 值
- 要使用 clearInterval() 方法, 在创建执行定时操作时要使用全局变量
var itemList = document.querySelectorAll('.item'); for (var i = 0; i < itemList.length; i++) { //处理交互事件 itemList[i].onmousedown = function (e) { if (e.buttons == 1) { if (this.classList.contains('flag') || this.classList.contains('q')) return; if (this.classList.contains('boom')) { alert('game over!'); clearInterval(timesum); } else // this open(this.id) } else if (e.buttons == 2) { if (this.classList.contains('q')) { this.classList.remove('q'); return; } else if (this.classList.contains('flag')) { this.classList.remove('flag'); this.classList.add('q'); boomsum++; display_boomsum(); return; } else if (!this.classList.contains('open')) { this.classList.add('flag'); boomsum--; display_boomsum(); if (boomsum <= 0) { if (check()) { alert('win'); clearInterval(timesum); } else { alert('lose'); clearInterval(timesum); } } } } } //禁用鼠标右键的默认行为 itemList[i].oncontextmenu = function () { return false } }
- open
- “打开盒子” 如果为除0以外的数字就显示其周围的炸弹数(cal函数),并改变字体颜色
- 如果为0,则不显示数字并递归打开周边的盒子
!!进行安全检查
- 注意
- open传递的值为id值,不需要拼字符串时加上#
- #是选择器,不要混
- id是字符串类型(在递归时需要进行拼接,需要将取处理的值强转为Number)
- 取id值时两种方法
- 直接取,如果id值标识行列都为个位数时,显示正常,如果有两位数表示时,会导致取行/列取不全
例如:
let temp = "_9_8"; var x = Number(temp[1]); //9 var y = Number(temp[3]); //8 let temp = "_9_10"; var x = Number(temp[1]); //9 var y = Number(temp[3]); //1
- 使用split(),将id切去不需要的,转为数组呈现
- 例如:
id = '_9_10' let temp = id.split('_');//temp = ['','9','10'] var x = Number(temp[1]);//9 var y = Number(temp[2]);//10
//open var open = function (id) { var el = document.getElementById(id); if (!el) return; else if (el.classList.contains('open')) return; else if (el.classList.contains('flag') || el.classList.contains('q')) return; //显示它周围的雷数 var num = cal(id); el.classList.add('open'); el.textContent = num; var colors = ['#414fbc', '#226301', '#ae0107', '#050085', '#050085', '#050085', '#050085', '#050085']; el.style.color = colors[num - 1]; if (num == 0) { el.textContent = ''; let temp = id.split('_'); var x = Number(temp[1]); var y = Number(temp[2]); for (var i = -1; i < 2; i++) { for (var j = -1; j < 2; j++) { // 不加# open('_' + (x + i) + '_' + (y + j)); } } } }
- cal函数 显示周围的炸弹数
document.querySelector('#_' + (x + i) + '_' + (y + j))?.classList.contains('boom')
- 通过函数document.querySelector()查询选择器为括号中的值,返回值是e
- 此时因为是选择器,所以需要#
- ?三目运算符,解决处于边角的盒子,周围有些方向的盒子没有的问题
//显示它周围的雷 var cal = function (id) { var total = 0; var temp = id.split('_'); var x = Number(temp[1]); var y = Number(temp[2]); for (var i = -1; i < 2; i++) { for (var j = -1; j < 2; j++) { if (document.querySelector('#_' + (x + i) + '_' + (y + j))?.classList.contains('boom')) total++; } } return total; }
- check()检查
//检查flag是否全是boom var check = function () { var result = true; let flagList = document.querySelectorAll('.flag') for (let i = 0; i < flags.length; i++) { if (!flagList[i].classList.contains('boom')) { result = false } } return result; }
5. 趣味效果
共勉