学写前端原生扫雷

最近看完了视频贪吃蛇和扫雷,都是非常经典的游戏,且代码较为简单,接下来记录上扫雷代码的过程。
先截个图,看看效果:
学写前端原生扫雷_第1张图片
首先html代码:

接下来是css代码:

*{                     /* 规范代码的习惯,去掉margin和padding的默认值 */
    margin: 0;
    padding: 0;
}

.wrapper{            /* 承载界面的设置  */
    width: 100%;           /* 100%的宽度 */
    height: 630px;          /* 按照自己电脑的浏览器设置的高度 */
    position: absolute;      /* 绝对定位 */
    left: 0;
    top: 0;
}

.box{                 /* 游戏主界面 */
    width: 300px;         /* 设置一个300*300的正方形 */
    height: 300px;
    border: 1px solid black;     /* 边框 */
    position: absolute;         /* 这到底表示的是基于父级定位的中心定位 */
    top: 0;
    left: 0;
    bottom: 0;
    right: 0;
    margin: auto;
}

.alertBox{             /* 游戏结束后的承载界面 */
    display: none;          /* 游戏开始不显示,在js中触发后显示 */
    position: absolute;     /*  绝对定位 */
    left: 0;
    top: 0;
    width: 100%;         /* 设置宽高 */
    height: 100%;
    background-color: rgba(0, 0, 0, 0.2);    /* 给承载界面一个背景颜色和透明度 */
}

.alertImg{              /* 游戏结束后出现的提示框 */
    position: absolute;      /* 基于父级定位的中心定位 */
    top: 0;
    left: 0;
    bottom: 0;
    right: 0;
    margin: auto;
    background-image: url('img/success.png');       /* 设置提示的图片 */
    background-size: 100% 100%;
    width: 300px;           /* 设置图片的宽高 */
    height: 200px;
}

.close{    /* 关闭按钮 */
    background-image: url('img/shanchu.png');      /* 关闭按钮图片 */
    background-size: 100% 100%;
    width: 30px;      /* 设置宽高 */
    height: 30px;
    position: absolute;        /* 基于父级的绝对定位 */
    top: 0;
    right: 0;
    cursor: pointer;         /* 当鼠标移动到该图片上面时,变为小手 */
}

上述的css代码还未完整,需要结合js里新建的div中设置class或id后,再补充。
接下来js:

var box = document.getElementById('box');      //获取到html中的id = ‘box’的节点,下面相同
var minesNum;
var mineOver;
var mineMap = [];
var block;
var closeBtn = document.getElementById('close');
var alertBox = document.getElementById('alertBox');
var alertImg = document.getElementById('alertImg');

bindEvent();                //触发bindEvent函数
function bindEvent(){
    init();            //触发init函数
    box.oncontextmenu = function(){          //取消box里的右键默认功能
      return false;
    }
    box.onmousedown = function(e){         //当box里被鼠标按键触发时
        var event = e.target;          //event获取到按键的目标
        if(e.which == 1){            //e.which = 1表示鼠标左键
            leftClick(event);      //触发该函数,携带event
        }else if(e.which == 3){        //e.which = 3表示鼠标的右键
            rightClick(event);     //同上
        }
    }
    closeBtn.onclick = function(){           //游戏结束后的图片右上角的图片触发的事件
        alertBox.style.display = 'none';        //游戏结束的提示图片消失
        box.innerHTML = '';           //去除掉玩过游戏后的剩余界面
        init();                            //重新触发游戏开始界面,开始新的一轮游戏
    }
}
function init(){               //游戏主界面的内容
    minesNum = 10;
    mineOver = 10;
    for(var i = 0; i < 10;i ++){          //循环10次
        for(var j = 0; j < 10;j ++){           //加上面的10次,循环100次,生成100个格子
            var con = document.createElement('div');         //生成格子
            con.classList.add('block');           //对格子添加class = ‘block’
            con.setAttribute('id',i+'-'+j);           //对每个格子添加不同的id = ‘i-j’(这里的i,j表示横纵格子的数字,如1-3表示第二行第四列,注这里的数字从0开始算)
            box.appendChild(con);             //html中的box显示出来con内容(将100*100格子显示在html中)
            mineMap.push({mine:0});   //每次生成小格子往数组里面传, 传一个参数mine 初始值0
        }
    }
    block = document.getElementsByClassName('block');    //得到class = ‘block’的节点,就是上面的小格子
    while(minesNum){
        var mineIndex = Math.floor(Math.random()*100);        //得到0-100中的随机数字
        if(mineMap[mineIndex].mine === 0){             //找到随机位置,且该位置初始时mine为0
            mineMap[mineIndex].mine = 1;            //防止同一位置重复生成雷
            block[mineIndex].classList.add('isLei');            //随机出现雷的标记
            minesNum --;        //该游戏中限制共10个雷,循环10次,埋10个雷
        }
    }
}
function leftClick(dom){       //左点击事件
 if(dom.classList.contains('flag')){       //当标记过旗子后不可左点击
        ;                                         //不执行任何事件
    }else{
    var isLei = document.getElementsByClassName('isLei');            //得到class = ‘isLei’的节点
    if(dom && dom.classList.contains('isLei')){           // 判断点击的是雷          contains返回布尔值,判断指定的类名是否存在。 
        for(var i = 0;i < isLei.length;i ++){                        //循环雷总数的次数,将所有的雷全部显示出来
            isLei[i].classList.add('show');             //点出后的雷添加上class = ‘show’
        }
        setTimeout(function(){
            alertBox.style.display = 'block';         //出现游戏结束的界面
            alertImg.style.backgroundImage = 'url("img/over.png")';        //游戏界面输了的图片
        },800);        //游戏失败后,800ms后出现上述事件
    }else{             //点击的不是雷时,触发的事件
        var n = 0;
        var posArr = dom && dom.getAttribute('id').split('-');       //得到按键目标上的格子的id值,取掉中间的-符号
        var posX = posArr && +posArr[0];      //得到目标格子上的第一个数字
        var posY = posArr && +posArr[1];        //得到目标格式上的第二个数字
        dom && dom.classList.add('num');         //为目标格子添加上class = ‘num’

        for(var i = posX - 1;i <= posX + 1;i ++){             //循环目标自己和左右三个格子
            for(var j = posY - 1; j <=posY + 1;j ++ ){            //循环目标格子自己和上下三个格子,共循环9次
                var aroundBox = document.getElementById(i+'-'+j);         //得到di = ‘i-j’的节点,就是得到目标格子上下左右9个格子
                if(aroundBox && aroundBox.classList.contains('isLei')){         //判断目标格子和周围是否有雷
                    n ++;       //目标格子周围有一个雷就+1
                }
            }
        }
        if(n != 0){         //当n不等于0时,显示出对应周围格子有雷个数情况
            dom && (dom.innerHTML = n);
        }else{           //等于0表示周围没有雷
            dom && (dom.innerHTML = '');            //没有雷,用空显示
        }
        if(n == 0){            //当n为0时,还需要继续判断它周围的周围是否有雷
            for(var i = posX - 1 ;i <= posX + 1;i ++){         //同上循环目标格子的周围9个(包括自己),表示9次循环
                for(var j = posY - 1;j <= posY + 1;j ++){
                    var nearBox = document.getElementById(i + '-' + j);     //得到格子上的id
                    if(nearBox && nearBox.length != 0){           //判断目标格子长度是否为0(即目标有没有周围的格子,有才能接着判断),不为0时才执行下列事件
                        if(!nearBox.classList.contains('check')){    //当格子上没有class = ‘check’时执行下列事件
                            nearBox.classList.add('check');            //为该格子加上class = ‘check’
                            leftClick(nearBox);             //再执行一次左击事件函数
                        }
                    }
                }
            }
        }
        if(document.getElementsByClassName('num').length == 90){       //判断被点击出的class = ‘num’的个数,由于该游戏时100*100的界面,且共有10个雷,即有90个num,当都被点击开后且没有触发到雷,即游戏赢了,所以触发下面的事件
            alertBox.style.display = 'block';
            alertImg.style.backgroundImage = 'url("img/success.png")';       //出现游戏赢了的图片
        }
    }
  }
}

function rightClick(dom){            //右键事件函数
    if(dom.classList.contains('num')){               //当右击的是已经被点开的格子,表示没反应,不执行任何事件
        return;
    }
    dom.classList.toggle('flag');           //给目标格子交替加入class = flag,点击一次出现,第二次消失,更替
    if(dom.classList.contains('isLei') && dom.classList.contains('flag')){     //目标格子有雷(class = ‘isLei’的节点)且有旗子(class = ‘flag’的节点)时触发事件
        mineOver --;         //雷的数量减少
    }
    if(!dom.classList.contains('isLei') && dom.classList.contains('flag')){       //没有雷,有旗
        mineOver ++;       //总显示雷数增加
    }
    if(dom.classList.contains('isLei') && !dom.classList.contains('flag')){          //有雷,没旗(感觉好像不存在这个语句也可以。。。,但是当你按的右键是第二次时就有用了!)
        mineOver ++;
    }
    if(!dom.classList.contains('isLei') && !dom.classList.contains('flag')){           //没雷,没旗
        mineOver --;
    }
    if(mineOver == 0){         //当所有的雷都被标记旗子后,表示游戏赢了,即出现游戏结束界面
        alertBox.style.display = 'block';
        alertImg.style.backgroundImage = 'url("img/success.png")';
    }
}

补全上述js中创建的class的css代码:`

.block{              //小格子的设置
    width: 29px;          //设置宽高,记得这里需要算上边框的1px
    height: 29px;
    border-right: 1px solid #b25f27 ;      //右边框
    border-bottom: 1px solid #b25f27 ;          //下边框
    box-shadow: 0 0 4px #333 inset;        //加点阴影
    background-color: #6493f8;         //格子颜色
    float: left;           //排齐格子
}

.show{       //显示炸弹
    background-image: url('img/zd.png');
    background-size: 100% 100%;
}

.num{         //显示数字
    background: #dddddd;        //颜色
    font-size: 12px;                //字体
    font-weight: bold;            //加粗
    line-height: 29px;   
    text-align: center;       //数字显示正中间

}

.flag{                   //显示旗子
    background-image: url('img/hq.png');
    background-size: 100% 100%;
}

代码以记录完毕,截几个图看看:
学写前端原生扫雷_第2张图片
学写前端原生扫雷_第3张图片
上述代码若有解释错误的,请指出,谢谢,若有不理解的可以留言,我会尽量及时回复的,谢谢

你可能感兴趣的:(javascript,html,前端js)