插件
// 使用闭包,解决$命名冲突问题
(function ($) {
/**
*
*/
function change() {
}
/**
* 对外提供的接口
*
* 必须传递 行 row,列 column,雷的个数 mine_num,显示画板的位置 obj 盒子的ID值
*/
$.fn.mineClearance = function (options) {
// console.log(options);
// var obj1 = {name:'张三',age:16};
// var obj2 = {name:'李四',addr:'石家庄'}
// 合并两个对象,如果有相同的属性,则使用后者替换前者
// 所以前者适合做默认值,后者适合做参数传递
// var obj3 = $.extend(obj1,obj2);
// console.log(obj3);
var settings = $.extend({
// 默认列
column: 10,
// 默认行
row: 10,
// 默认雷个数
mine_num: 20,
// 默认画板ID
obj: "#content",
// 每一个div盒子,默认是空数组
tiles: [],
// 周边8个元素
arr: [],
// 判断游戏是否是第一点击,如果是第一次就初始化雷,true表示第一次点击
flag: true
}, options || {});
// 生成画板
buildTiles();
/**
* 生成画板
*/
function buildTiles() {
// 判断行和列是否合法
if (settings.column <= 0 || settings.row <= 0) {
alert('行和列必须大于 0 哦~');
return;
}
// 判断雷
if (settings.mine_num <= 0) {
alert("没雷你玩啥?");
return;
}
if (settings.mine_num >= (settings.column * settings.row)) {
alert("全是雷");
return;
}
// 到这里说明数据没啥问题
// 获取画板的DOM对象
var obj = $(settings.obj);
// 设置画板的宽高
// 每个盒子宽高是49,边框都是1,所以实际宽高为 51
// 画板的宽度 = 列数 * 51
// obj.style.width = 51 * settings.column + "px";
// obj.style.height = 51 * settings.row + "px";
obj.width(51 * settings.column);
obj.height(51 * settings.row);
// 对div添加索引,0,1,2,3,.....
// 方便我们操作,我们能够根据点击的是谁,获取它和周边8个元素
// 比如 3行4列, 我们点的是第6个,索引就是 5
// 5 % 列数 = 1
// (5-1) / 列数 = 1
var indexOfdiv = 0;
// 根据行和列 生成div 并设置索引
for (var i = 0; i < settings.row; i++) {
for (var j = 0; j < settings.column; j++) {
// 创建div标签
// var tile = document.createElement("div");
var tile = $('<div class="tile"></div>');
// 设置class属性值为 tile
// tile.className = 'tile';
// 添加索引
// tile.setAttribute('index',indexOfdiv);
tile.attr('index', indexOfdiv);
// 把div保存到 settings.tiles数组中,方便我们后续操作
settings.tiles[indexOfdiv] = $(tile);
indexOfdiv++;
// 把div添加到 画板中
// obj.appendChild(tile);
obj.append(tile);
}
}
//清空事件,避免叠加事件
obj.unbind();
// 绑定事件
event();
}
/**
* 对div绑定事件
*/
function event() {
// 获取画板对象
var obj = $(settings.obj);
// 对画板绑定事件,通过事件源,找到真正触发的这个小div即可
// 移入
obj.mouseover(function (e) {
// 如果class属性值不是tile ,
// 说明要么你移动到已经点击过的div
// 要么你移动到边框上,就是画板了
// 我们只对未点击过的div做移入事件
if ($(e.target).attr('class') == 'tile') {
$(e.target).attr('class','tile current') ;
//添加音乐
$('#move')[0].play();
}
});
// 移出
obj.mouseout(function (e) {
// 如果class属性值不是tile ,
// 说明要么你移动到已经点击过的div
// 要么你移动到边框上,就是画板了
// 我们只对未点击过的div做移入事件
if ($(e.target).attr('class') == 'tile current') {
$(e.target).attr('class','tile') ;
//取消音乐
$('#move')[0].pause();
}
});
// 右键事件,添加小红旗
obj.contextmenu(function (e) {
// 当右键的时候,如果不是雷,不是已点击的,就可以添加红旗
// 因为如果是boom雷的时候,说明游戏已经结束
if ($(e.target).attr('class') != 'boom' && $(e.target).attr('class') != 'showed') {
// e.target.className = 'tile';
// console.log(e.target.className);
// if(e.target.className.split(' ').length == 3){
// e.target.className = 'tile current'
// }else{
// e.target.className = 'tile current tag'
// }
$(e.target).toggleClass('tag');
}
return false;
});
// 点击事件
obj.click(function (e) {
// alert(22);
if ($(e.target).hasClass('tile')) {
// 获取事件源索引
// var index = e.target.index;
var index = $(e.target).index();
// console.log(index);
// 判断点击的是否含有小红旗
// class属性是否包含 tag
// console.log(e.target.classList.contains('tag'));
if ($(e.target).hasClass('tag')) {
alert("请先右键取消小红旗");
return;
}
}
$('#click')[0].play();
// 到这里 说明点击的不是小红旗
// 初始化所有div , 生成雷,判断周边几个雷
changeStyle($(e.target), index);
});
}
/**
* 生成雷,统计周围雷的个数等
*
* 第一个参数 : 点击的元素
* 第二个参数 : 该元素的index索引
*/
function changeStyle(obj, num_index) {
// 判断是否是第一次点击
if (settings.flag) {
// 是的话,生成雷等信息
// 获取周围八个元素
// store(num_index);
// 生成雷,val 表示,1是雷,0不是雷
setMineCraft();
settings.flag = false;
}
/**
* 初始化操作已完成
*/
// 雷和周边雷个数 已完成,需判断点击之后,是否是雷,是否游戏结束(胜利和失败),不是雷就需要进行扩散显示
// 不是就判断点击的是否是雷
// 判断游戏是否结束 - 胜利, 失败
if (!obj.attr('val')) {
// 设置为已点击状态
// obj.className = 'showed';
obj.attr('class', 'showed');
// 显示周围几个雷
// let value = obj.getAttribute('value');
let value = obj.attr('value');
obj.html(value) == 0 ? '' : value;
// 扩散显示
showAll(obj.index());
}
// 判断游戏是否结束,如果结束,显示所有div信息
// 比如 是雷的 就替换成雷的图片,周围有几个雷 就显示几
if (over(obj)) {
// 进来说明游戏结束
// 显示所有div信息
show();
}
}
/**
* 游戏结束 重置div,所有信息都显示
*/
function show() {
// 思路 : 遍历所有div 判断val是1是0 是 设置class为 boom 是0 设置class为 showed
for (var i = 0; i < settings.tiles.length; i++) {
// settings.tiles[i].className = settings.tiles[i].getAttribute('val') == 1 ? 'boom' : 'showed';
// console.log($(settings.tiles[i].addClass('val')));
// $(settings.tiles[i]).addClass($(settings.tiles[i]).attr('val') ==1 ? 'boom' : 'showed') ;
$(settings.tiles[i]).attr('class', $(settings.tiles[i]).attr('val') == 1 ? 'boom' : 'showed')
// 如果不是雷 就要显示周边几个雷
if ($(settings.tiles[i]).attr('class') != 'boom') {
var value = $(settings.tiles[i]).attr('value');
$(settings.tiles[i]).html(value) == 0 ? '' : value;
}
}
// 取消事件
$(settings.obj).unbind('click');
}
/**
* 游戏结束判断
*
* @param {点击的元素} obj
*/
function over(obj) {
// true说明结束,false说明没有结束
var flag = false;
// 如何算游戏胜利 : 已点击的 + 雷的个数 = 总div个数
// 获取已点击的元素
var showed = $('.showed');
// div总个数 减去 雷的个数,得到剩余div个数
var num = settings.tiles.length - settings.mine_num;
if (num == showed.length) {
$('#victory')[0].play();
alert("恭喜你获得成功~");
flag = true;
// 如何算失败 : 点到雷就失败 val == 1
} else if (obj.attr('val') == 1) {
$('#boom')[0].play();
alert('被炸死,游戏结束!');
$('#gameover')[0].play();
flag = true;
}
// 没结束 就返回false,继续游戏
return flag;
}
/**
* 判断周围是否是雷,如果不是雷,就全部显示
*
* 如果周围有雷,就不再进行遍历
*
* @param {点击元素的索引} num
*/
function showAll(num) {
// 判断 周围是否有雷
// 如果有 终止
// 如果没有,遍历周边元素的周边元素,依次判断
// console.log($(settings.tiles[num]).attr('class') == 'showed'==$(settings.tiles[num]).attr('value'));
if ($(settings.tiles[num]).attr('class') == 'showed' && $(settings.tiles[num]).attr('value') == 0) {
// 获取周边8个(settings.arr)
store(num);
// 如果递归,会更改arr的值,所以保存为局部变量
var arr2 = settings.arr;
// 非showed
for (var i = 0; i < arr2.length; i++) {
// 如果添加小红旗标识 就跳过该次循环
// console.log($(arr2[i]).hasClass('tag'));
if ($(arr2[i]).hasClass('tag')) {
continue;
}
if ($(arr2[i]).attr('class') != 'showed') {
// value == 0
// 判断周边8个是否有雷,没有就显示并递归
if ($(arr2[i]).attr('value') == 0) {
// true 递归
// arr2[i].className = 'showed';
$(arr2[i]).attr('class', 'showed');
// console.log($(arr2[i]).index());
showAll($(arr2[i]).attr('value'));
} else {
// false 设置为showed并显示value
// arr2[i].className = 'showed';
$(arr2[i]).attr('class', 'showed');
// arr2[i].innerHTML = arr2[i].getAttribute('value');
$(arr2[i]).html($(arr2[i]).attr('value'));
}
}
}
}
}
/**
* 生成雷,val 表示,1是雷,0不是雷
*/
function setMineCraft() {
// 雷的个数
var num = settings.mine_num;
// 遍历所有div 设置不是雷
// for (var i = 0; i < settings.tiles.length; i++) {
// settings.tiles[i].setAttribute('val', 0);
// }
// 随机生成雷
for (var i = 0; i < num; i++) {
// 随机的雷的索引
var index_Mine = Math.floor(Math.random() * settings.tiles.length);
// 判断生成的索引 是否生产过雷
// console.log(settings.tiles[index_Mine].getAttribute("val"));
if (!$(settings.tiles[index_Mine]).attr("val")) {
// 没有 就设置为 雷
$(settings.tiles[index_Mine]).attr('val', 1);
} else {
// 如果生产过 就不搭理,但是 i要-1 否则 最终雷的个数就会少
i--;
}
}
// 设置value值,点击之后 显示周围有几个雷
showValue();
}
/**
* 设置value值,点击之后 显示周围有几个雷
*
* 比如周围8个有一个类 就显示1
*/
function showValue() {
// 1 对所有不是雷的元素 设置内容
// 2 获取每个非雷元素的周边8个盒子
// console.log(settings.tiles.length);
for (var i = 0; i < settings.tiles.length; i++) {
// 判断是否是雷,是就跳过
if ($(settings.tiles[i]).attr('val') == 1) {
continue;
}
// 如果不是雷,就获取周边8个元素,传递当前元素的索引 index
store($(settings.tiles[i]).index());
// console.log(settings.arr);
// 3 遍历8个盒子,对雷的个数进行计数 arr
var count = 0;
for (var j = 0; j < settings.arr.length; j++) {
if ($(settings.arr[j]).attr('val') == 1) {
count++;
}
}
// 4 把计数结果 设置到 当前div的内容当中
// if (count != 0) {
// settings.tiles[i].innerHTML = count;
// settings.tiles[i].setAttribute('value', count);
$(settings.tiles[i]).attr('value', count);
// }
}
}
/**
* 获取周围八个元素
* @param {点击的元素的索引} num
*/
function store(num) {
/**
* settings.tiles 转换为二维数组,方便查找周边八个元素
*/
// var tiles_2d = [];
// 当做 settings.tiles的下标
// var indexs = 0;
// 遍历settings.tiles 封装到二维数组中
// for (var i = 0; i < settings.row; i++) {
// // 二维数组中 添加一个空的一维数组
// tiles_2d.push([]);
// for (var j = 0; j < settings.column; j++) {
// tiles_2d[i].push(settings.tiles[indexs]);
// indexs++;
// }
// }
// 根据点击的元素的索引 获取在二维数组中的下标
// var j = num % settings.column;
// var i = (num - j) / settings.column;
// 对settings.arr 初始化
settings.arr = [];
var index = num;
var c = settings.column;
var r = settings.row;
// 左上
if (index % c > 0 && index - c >= 0) {
settings.arr.push(settings.tiles[index - c - 1]);
}
// 正上
if (index - c >= 0) {
settings.arr.push(settings.tiles[index - c]);
}
// 右上
if (index - c >= 0 && index % c < c - 1) {
settings.arr.push(settings.tiles[index - c + 1]);
}
// 左边
if (index % c > 0) {
settings.arr.push(settings.tiles[index - 1]);
}
// 右边
if (index % c < c - 1) {
settings.arr.push(settings.tiles[index + 1]);
}
// 左下
if (index % c > 0 && index + c < c * r) {
settings.arr.push(settings.tiles[index + c - 1]);
}
// 正下
if (index + c < c * r) {
settings.arr.push(settings.tiles[index + c]);
}
// 右下
if (index % c < c - 1 && index + c < c * r) {
settings.arr.push(settings.tiles[index + c + 1]);
}
// console.log(settings.arr);
}
}
})(jQuery);
css
{
margin: 0;
padding: 0;
}
body{
text-align: center;
font-size: 15px;
font-family: ‘楷体’;
}
#content{
/ border: 1px solid; /
/ width: 200px; /
margin: 0 auto;
}
/ 重新加载 /
#refresh{
/ 设置行内块,否则不能设置宽高 /
display: inline-block;
width: 100px;
height: 30px;
/ 行高和高度一致,则内容垂直居中 /
line-height: 30px;
border: 1px solid gray;
/ 圆角边 /
border-radius: 5px;
/ 小手状 */
cursor: pointer;
color: white;
background-color: rgb(143,122,102);
}
/* 每一个div小格子 /
/ 默认 */
#content div{
width: 48px;
height: 49px;
border: 1px solid black;
text-align: center;
font-size: 20px;
line-height: 49px;
cursor: pointer;
float: left;
}
.tile{
background: url(…/img/ba.png);
}
/* 已点击 */
.showed{
background: rgb(195,206,228);
/* background-color: red; */
}
/* 雷 /
.boom{
background: rgb(195,206,228) url(…/img/Minesmall.png);
}
/ 移入 */
.current{
background: url(../img/baq.png);
}
/* 小红旗 /
.tag{
/ 第一个是前景,第二个是背景 */
background: url(…/img/hq.png),url(…/img/ba.png);
}
布局