鼠标左右键同时按下展开 提示雷区
js不自带监听鼠标左右键同时按下的事件,需要用mousedown进行模拟。
空白区(eBlock)不会触发这个事件
_bindEvent: function _bindEvent() {
var _this = this;
$('.Block').on("mousedown", function(e) {
//重设标志
_this.$checkFlag = false;
//阻止默认
$(e.target).bind("contextmenu", function() {
return false;
});
//二次点击判定
if(_this.$firstClick != null) {
_this.$secondClick = e.which;
if(_this.$secondClick === _this.$firstClick) {
_this.$secondClick = null;
_this.$firstClick = null;
return;
} else {
_this.$checkFlag = true;
//点击是文字
if(e.target.nodeName === "SPAN") {
var $spanValue = $(e.target).text();
e.target = e.target.parentNode;
}
//不接受空白块
if($(e.target).hasClass("eBlock")) return;
//得到位置
var $index = $('.Block').index($(e.target));
var $clickX = Math.floor($index / 18);
var $clickY = $index % 18;
var $indexItem;
var $indexItemCtn = [];
var $flagAns = 0;
var setColor = function(index) {
if($($('.Block')[index]).hasClass("eBlock") || $($('.Block')[index]).hasClass("enBlock")) return;
if($($('.Block')[index]).hasClass("fBlock")) {
$flagAns++;
return;
}
$indexItemCtn.push(index);
$($('.Block')[index]).addClass("Block-judge");
}
//边界鉴定
setColor($index);
if($clickX != 0) {
$indexItem = ($clickX - 1) * 18 + $clickY;
setColor($indexItem);
}
if($clickY != 0) {
$indexItem = $clickX * 18 + $clickY - 1;
setColor($indexItem);
}
if($clickX != 17) {
$indexItem = ($clickX + 1) * 18 + $clickY;
setColor($indexItem);
}
if($clickY != 17) {
$indexItem = $clickX * 18 + $clickY + 1;
setColor($indexItem);
}
if($clickY != 0 && $clickX != 0) {
$indexItem = ($clickX - 1) * 18 + $clickY - 1;
setColor($indexItem);
}
if($clickY != 17 && $clickX != 0) {
$indexItem = ($clickX - 1) * 18 + $clickY + 1;
setColor($indexItem);
}
if($clickY != 17 && $clickX != 17) {
$indexItem = ($clickX + 1) * 18 + $clickY + 1;
setColor($indexItem);
}
if($clickY != 0 && $clickX != 17) {
$indexItem = ($clickX + 1) * 18 + $clickY - 1;
setColor($indexItem);
}
//数值鉴定
$indexItemCtn.forEach(function(item, index) {
//只接受带值块
if($flagAns != $spanValue) return;
if(!$(e.target).hasClass("enBlock")) return;
if($spanValue == null) return;
var $checkX = Math.floor(item / 18);
var $checkY = item % 18;
//展开
if(map[$checkX][$checkY] == -1) {
//雷
_this._clickMines(null, item);
} else if(map[$checkX][$checkY] == 0) {
//空白区
_this._clickEmpty(null, $checkX, $checkY);
} else {
//雷域
_this._clickMinesArray(null, $checkX, $checkY);
}
});
}
} else {
_this.$firstClick = e.which;
}
});
},
当第一次点击触发mousedown时记录e.which(左键为1 右键为3),在不触发mouseup的过程中再次触发mousedown,记录第二次的e.which 若两次点击的值相同,则是双击左键或右键,不予处理,反之触发逻辑:通过算法演算点击值的八向坐标(同样需要边界鉴定),将其标黑(提示UI),并设置checkFlag为true,当checkFlag为true的情况下触发mouseup,取消标黑并进行演算,若八向的旗方块数量等于Block中的数值,则模拟点击周围未被点击的方块(会触发炸弹方块或者空白方块)。
收尾
其他的需求
- 计时器
- 炸弹数量提示
这部分不作赘述,计时器触发在第一次点击之后,用setTimeout进行模拟,炸弹数量变化触发在设置flag之后。
总结
若将扫雷的所有的算法实现,可能过程并不简单,甚至算法比较复杂。
但是实际上这个项目比起算法更考验的是项目的构架,如何让事件互相触发而不冲突,又如何模拟一些UI的操作,对基础的要求并不低。
项目的构架在文章中并不能体现出来,各位可以参考我的github源码,至此扫雷的核心实现方法已经全部详述了,希望各位对这个练手项目有兴趣的可以试试,因为他并不算简单,非常适合基础和进阶的锻炼,若本文对你有所帮助,记得去github给我加颗星星噢。
扫雷完整项目github地址 https://github.com/xxx407410849/MinesSweeper
若本文对您有帮助请给我的git项目加个星星哦