手把手教弟弟写了个扫雷demo,弟弟竟拿去跟大学同学装* 附(思路注释+源码)

js实现扫雷demo💣

先睹为快:😉

在这里插入图片描述

思路:🌀

  1. 创建地图,随机生成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里面的数字都没有展开
    }
  1. 创建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';
    }
  1. 判断一个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
    }
  1. 如果div在地图中间,周围有八个相邻的div,如果div在四个边界那么分别周围只有5个相邻的div,如果div是在地图四个角落,周围分别只有3个相邻的div
    例:
    在地图中间
    在这里插入图片描述
    在地图边界
    在这里插入图片描述
    在地图四个角落
    在这里插入图片描述

  2. 根据随机一个div在这100个div中是第几个来找出它周围相邻的div
    例:
    在这里插入图片描述
    中间的div是在这100个div 中的第25个,设它的下标为25,那么它正上发的div就是15,它正右边的就是26,它右下角的div就是36,依次类推🍄

  3. 定义一个数组将它周围的div的下标存起来,也就是第几个div,遍历这个数组,判断它周围有几个div 📏

  4. 遍历这个数组的时候需要分情况,也就是div在地图边界和在地图四个角落

  5. 如果div在地图的上边界那个遍历的时候 它的周围不能有 -11 -10 -9的div。如果div在地图的左边界的时候,它的周围不能有-1,9,-11的div。依次类推…

  6. 判断周围div下标是不是真正的地雷,遍历得出他们周围有几个雷的个数,放入在div中
    在这里插入图片描述

  7. 将地雷隐藏起来,给每个div绑定点击事件,左击排雷,右击标雷。如果this是雷,地雷全部爆炸(地雷全部标红,显示地雷),并将所有雷的数字显示出来。

  8. 左键排雷,没有踩雷的话,就把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)

            }
  1. 右击事件标雷,设置蓝色显示
    在这里插入图片描述
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);








觉得博主总结的不错的,可以收藏支持一波~     🐵



在这里插入图片描述

评论 282
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

贪吃ღ大魔王

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值