js实现扫雷demo💣
先睹为快:😉
思路:🌀
- 创建地图,随机生成100个div盒子,设置相应样式
var container = document.querySelector('.container')
// 动态创建100个小div放在container里面
var mineWidth = 50;
var mineHeight = 50;
// 求小div的数量
var mineNum = container.clientWidth * container.clientHeight / (mineWidth * mineHeight)
// 求一行几个
var mineColNum = container.clientWidth / mineWidth;
// 循环创建
for (var i = 0; i < mineNum; i++) {
var div = document.createElement('div')
Tool.setStyle(div, {
width: mineWidth - 2 + "px",
height: mineHeight - 2 + "px",
backgroundColor: "#ccc",
border: "1px solid #fff",
position: "absolute",
left: (i % mineColNum) * mineWidth + "px",
top: parseInt(i / mineColNum) * mineHeight + "px",
textAlign: "center",
lineHeight: "50px"
})
container.appendChild(div)
div.mine = false // 表示所有div初始都不是雷
this.show = false; // 表示所有div里面的数字都没有展开
}
- 创建10个地雷,在地图中位置随机产生💣
// 标记雷
// 定义一个用来存放雷div的下标的数组
var arr = [];
for (var i = 0; i < 10; i++) {
// 获取随机下标
var index = Math.floor(Math.random() * 100)
// 判断数组中是否已经有了这个下标
if (arr.indexOf(index) < 0) {
arr.push(index)
} else {
i--
}
}
// 遍历所有雷div的下标数组,给是雷的div标记
for (var i = 0; i < arr.length; i++) {
container.children[arr[i]].mine = true
// container.children[arr[i]].style.backgroundColor = 'red';
}
- 判断一个div的周围有几个地雷,并将相应的数量给这个div,那么怎么找呢?往以下步骤看
// 定义一个数组,将周围div的下标存起来
var brr = [-11, -10, -9, -1, 1, 9, 10, 11];
// 遍历每个div周围的div
// 遍历这个100个div
for (var i = 0; i < container.children.length; i++) {
// 如果当前这个div是雷就统计了
if (container.children[i].mine) {
continue;
}
// container.children[i] // 每个div
// 查看当前div周围的所有div
// 定义周围雷数量的变量
var num = 0
for (var j = 0; j < brr.length; j++) {
// 考虑最上面一行 - 不能-11 不能-10 不能-9
if (i < mineColNum && (brr[j] === -11 || brr[j] === -10 || brr[j] === -9)) {
continue;
}
// // 最左边一行过滤掉
if (i % mineColNum === 0 && (brr[j] === -11 || brr[j] === -1 || brr[j] === 9)) {
continue;
}
// 最下面一行
if (parseInt(i / mineColNum) === mineColNum - 1 && (brr[j] === 9 || brr[j] === 10 || brr[j] === 11)) {
continue;
}
// 最右边一行
if (i % mineColNum === mineColNum - 1 && (brr[j] === -9 || brr[j] === 1 || brr[j] === 11)) {
continue;
}
if (container.children[i + brr[j]].mine) {
num++
}
}
// 将雷的数量放在div中
container.children[i].num = num
}
-
如果div在地图中间,周围有八个相邻的div,如果div在四个边界那么分别周围只有5个相邻的div,如果div是在地图四个角落,周围分别只有3个相邻的div
例:
在地图中间
在地图边界
在地图四个角落
-
根据随机一个div在这100个div中是第几个来找出它周围相邻的div
例:
中间的div是在这100个div 中的第25个,设它的下标为25,那么它正上发的div就是15,它正右边的就是26,它右下角的div就是36,依次类推
🍄 -
定义一个数组将它周围的div的下标存起来,也就是第几个div,遍历这个数组,判断它周围有几个div 📏
-
遍历这个数组的时候需要分情况,也就是div在地图边界和在地图四个角落
-
如果div在地图的上边界那个遍历的时候 它的周围不能有 -11 -10 -9的div。如果div在地图的左边界的时候,它的周围不能有-1,9,-11的div。依次类推…
-
判断周围div下标是不是真正的地雷,遍历得出他们周围有几个雷的个数,放入在div中
-
将地雷隐藏起来,给每个div绑定点击事件,左击排雷,右击标雷。如果this是雷,地雷全部爆炸(地雷全部标红,显示地雷),并将所有雷的数字显示出来。
-
左键排雷,没有踩雷的话,就把this周围的雷的数量显示出来(显示绿色)
if (this.mine) {
// 如果点击到雷了
for (var j = 0; j < container.children.length; j++) {
// 给所有不是雷的div设置内容显示,雷的数量
container.children[j].innerText = container.children[j].num ? container.children[j].num : '';
container.children[j].style.backgroundColor = '#0f0';
}
// 将所有是雷的div设置为红色
for (var j = 0; j < arr.length; j++) {
container.children[arr[j]].style.backgroundColor = 'red';
}
} else {
// 如果不是雷
// this.innerText = this.num;
// this.style.backgroundColor = '#0f0';
// this.show = true // 表示当前这个div已经展开了
openAround(this.index)
}
- 右击事件标雷,设置蓝色显示
container.children[i].oncontextmenu = function () {
this.style.backgroundColor = 'blue';
return false;
}
}
细节处理: 🚴
- 如果踩雷,将他的内容设为空,而不是undefined。
- 如果踩雷,给所有不是雷的div设置内容显示(绿色,雷的数量),将雷的div设为红色
- 判断自己周围的div是否是0,把周围div打开,用递归将刚刚打开的div继续判断自己是否是0
// 打开周围div的递归函数
function openAround(index) {
container.children[index].innerText = container.children[index].num
container.children[index].style.backgroundColor = '#0f0'
container.children[index].show = true
if (container.children[index].num === 0) {
container.children[index].style.backgroundColor = 'pink';
for (let j = 0; j < brr.length; j++) {
if (index < mineColNum && (brr[j] === -11 || brr[j] === -10 || brr[j] === -9)) {
continue;
}
// // 最左边一行过滤掉
if (index % mineColNum === 0 && (brr[j] === -11 || brr[j] === -1 || brr[j] === 9)) {
continue;
}
// 最下面一行
if (parseInt(index / mineColNum) === mineColNum - 1 && (brr[j] === 9 || brr[j] === 10 || brr[j] === 11)) {
continue;
}
// 最右边一行
if (index % mineColNum === mineColNum - 1 && (brr[j] === -9 || brr[j] === 1 || brr[j] === 11)) {
continue;
}
if (container.children[index + brr[j]].show) {
continue
}
openAround(index + brr[j])
}
}
}
更多详细注释 in 源码 ☕
源码:✨
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>document</title>
</head>
<style>
.container {
width: 500px;
height: 500px;
margin: 50px auto;
border: 3px solid #999;
position: relative;
}
</style>
<body>
<div class="container">
</div>
</body>
<script src="./js/tool.js"></script>
<script>
var container = document.querySelector('.container')
// 动态创建100个小div放在container里面
var mineWidth = 50;
var mineHeight = 50;
// 求小div的数量
var mineNum = container.clientWidth * container.clientHeight / (mineWidth * mineHeight)
// 求一行几个
var mineColNum = container.clientWidth / mineWidth;
// 循环创建
for (var i = 0; i < mineNum; i++) {
var div = document.createElement('div')
Tool.setStyle(div, {
width: mineWidth - 2 + "px",
height: mineHeight - 2 + "px",
backgroundColor: "#ccc",
border: "1px solid #fff",
position: "absolute",
left: (i % mineColNum) * mineWidth + "px",
top: parseInt(i / mineColNum) * mineHeight + "px",
textAlign: "center",
lineHeight: "50px"
})
container.appendChild(div)
div.mine = false // 表示所有div初始都不是雷
this.show = false; // 表示所有div里面的数字都没有展开
}
// 标记雷
// 定义一个用来存放雷div的下标的数组
var arr = [];
for (var i = 0; i < 10; i++) {
// 获取随机下标
var index = Math.floor(Math.random() * 100)
// 判断数组中是否已经有了这个下标
if (arr.indexOf(index) < 0) {
arr.push(index)
} else {
i--
}
}
// 遍历所有雷div的下标数组,给是雷的div标记
for (var i = 0; i < arr.length; i++) {
container.children[arr[i]].mine = true
// container.children[arr[i]].style.backgroundColor = 'red';
}
// 定义一个数组,将周围div的下标存起来
var brr = [-11, -10, -9, -1, 1, 9, 10, 11];
// 遍历每个div周围的div
// 遍历这个100个div
for (var i = 0; i < container.children.length; i++) {
// 如果当前这个div是雷就统计了
if (container.children[i].mine) {
continue;
}
// container.children[i] // 每个div
// 查看当前div周围的所有div
// 定义周围雷数量的变量
var num = 0
for (var j = 0; j < brr.length; j++) {
// 考虑最上面一行 - 不能-11 不能-10 不能-9
if (i < mineColNum && (brr[j] === -11 || brr[j] === -10 || brr[j] === -9)) {
continue;
}
// // 最左边一行过滤掉
if (i % mineColNum === 0 && (brr[j] === -11 || brr[j] === -1 || brr[j] === 9)) {
continue;
}
// 最下面一行
if (parseInt(i / mineColNum) === mineColNum - 1 && (brr[j] === 9 || brr[j] === 10 || brr[j] === 11)) {
continue;
}
// 最右边一行
if (i % mineColNum === mineColNum - 1 && (brr[j] === -9 || brr[j] === 1 || brr[j] === 11)) {
continue;
}
if (container.children[i + brr[j]].mine) {
num++
}
}
// 将雷的数量放在div中
container.children[i].num = num
}
// 点击
for (var i = 0; i < container.children.length; i++) {
container.children[i].index = i
container.children[i].onclick = function () {
if (this.mine) {
// 如果点击到雷了
for (var j = 0; j < container.children.length; j++) {
// 给所有不是雷的div设置内容显示,雷的数量
container.children[j].innerText = container.children[j].num ? container.children[j].num : '';
container.children[j].style.backgroundColor = '#0f0';
}
// 将所有是雷的div设置为红色
for (var j = 0; j < arr.length; j++) {
container.children[arr[j]].style.backgroundColor = 'red';
}
} else {
// 如果不是雷
// this.innerText = this.num;
// this.style.backgroundColor = '#0f0';
// this.show = true // 表示当前这个div已经展开了
openAround(this.index)
}
}
container.children[i].oncontextmenu = function () {
this.style.backgroundColor = 'blue';
return false;
}
}
// 打开周围div的递归函数
function openAround(index) {
container.children[index].innerText = container.children[index].num
container.children[index].style.backgroundColor = '#0f0'
container.children[index].show = true
if (container.children[index].num === 0) {
container.children[index].style.backgroundColor = 'pink';
for (let j = 0; j < brr.length; j++) {
if (index < mineColNum && (brr[j] === -11 || brr[j] === -10 || brr[j] === -9)) {
continue;
}
// // 最左边一行过滤掉
if (index % mineColNum === 0 && (brr[j] === -11 || brr[j] === -1 || brr[j] === 9)) {
continue;
}
// 最下面一行
if (parseInt(index / mineColNum) === mineColNum - 1 && (brr[j] === 9 || brr[j] === 10 || brr[j] === 11)) {
continue;
}
// 最右边一行
if (index % mineColNum === mineColNum - 1 && (brr[j] === -9 || brr[j] === 1 || brr[j] === 11)) {
continue;
}
if (container.children[index + brr[j]].show) {
continue
}
openAround(index + brr[j])
}
}
}
</script>
</html>
引入的工具库 tool.js 源码:
const Tool = (function () {
class Tool {
constructor() {
if (window.getComputedStyle) {
this.flag = true;
} else {
this.flag = false;
}
}
// 获取节点属性
getStyle (ele, attr) {
if (this.flag) {
return window.getComputedStyle(ele)[attr];
} else {
return ele.currentStyle[attr];
}
}
getStyle (ele, attr) {
// 尝试一段代码 不知道会不会报错
// 尝试成功 后面代码没有什么事
// 尝试失败 会报错 被cathch 捕获到 会将错误信息放到err参数里 catch{} 里可以处理这个错误 也可以不处理这个错误对上面的错误代码进行补救 错误不会再浏览器里报错
try {
return window.getComputedStyle(ele)[attr];
} catch (err) {
return ele.currentStyle[attr];
}
}
// 设置节点css属性
setStyle (ele, styleObj) {
for (let attr in styleObj) {
ele.style[attr] = styleObj[attr];
}
}
// 设置cookie
setCookie (key, value, second, path = '/') {
let data = new Date();
date.setTime(date.getTime() - 8 * 3600 * 1000 + second * 1000);
document.cookie = `${key}=${value};expires=${date};path=${path}`;
}
}
var tool;
return (function () {
if (!tool) {
tool = new Tool();
}
return tool;
})();
})();
// var f = tool();
// var t = f();
// var t = Tool();
// console.log(t);
// try {
// console.log(as);
// } catch (err) {
// console.log(err);
// }
// console.log(123);
觉得博主总结的不错的,可以收藏支持一波~ 🐵