2021.11.24 晴
运用JavaScript实现扫雷游戏
HTML
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<!--
tile 默认 ba.png
showed 已点击 #C3CEE5
boom 雷 Minesmall.png
tag 小红旗 hq.png
current 移入 baq.png
-->
<link rel="stylesheet" href="sl.css">
<script src="./jq/jq3.4.1.js"></script>
<script src="sl.js"></script>
<script>
window.onload = init;
function init() {
// 行列
var r_cArr = [10, 15, 20];
// 雷的个数
var mineArr = [10, 30, 80];
// 重新加载
var isstopmp3a=0;
document.getElementById('refresh').onclick = function () {
window.location.reload();
}
document.getElementById('start').onclick = function () {
//背景音乐
var mp3a=new Audio("./mp3/a.mp3");
$(mp3a).bind('ended',function(){
mp3a.play();
if(isstopmp3a==1){
mp3a.pause();
return;
}
})
mp3a.play();
// alert('开始游戏');
// 0 判断游戏是否已经开始
var content = document.getElementById('content');
content.innerHTML = '';
// 1 获取选择的难度
var value = document.getElementById('set_num').value;
// console.log(value);
// 2 获取雷的个数还有行和列
var mineNum = mineArr[value];
var r_c = r_cArr[value];
//自定义
var getRow = document.getElementById('getRow');
var getColumn = document.getElementById('getColumn');
var getMine = document.getElementById('getMine');
var row1 = parseInt(getColumn.value);
var column1 = parseInt(getColumn.value);
var mine1 = parseInt(getMine.value);
if (row1 > 6 && column1 > 6 && mine1<row1*column1/2) {
mineClearance(row1, column1, mine1)
return;
}
// 执行
mineClearance(r_c, r_c, mineNum);
}
}
</script>
</head>
<body>
<select name="" id="set_num">
<option value="0">初级</option>
<option value="1">中级</option>
<option value="2">高级</option>
</select>
<button id="start">确定</button>
<span id='refresh'>重新加载游戏</span>
<div class="self_defining">行数:<input type="text" id="getRow"></div>
<div class="self_defining">列数:<input type="text" id="getColumn"></div>
<div class="self_defining">雷的数量:<input type="text" id="getMine"></div>
<div id="content">
<!-- <div class="tile">默认</div>
<div class="tile">默认</div>
<div class="tile">默认</div>
<div class="tile">默认</div>
<div class="showed">2</div>
<div class="boom">雷</div>
<div class="tile tag">小红旗</div>
<div class="tile current">鼠标移入</div> -->
</div>
</body>
</html>
CSS
*{
margin: 0;
padding: 0;
text-align: center;
font-size: 15px;
font-family: '楷体';
}
#content{
margin: 0 auto;
}
/* 重新加载游戏 */
#refresh{
display: inline-block;
height: 30px;
width: 100px;
line-height: 30px;
border: 1px solid gray;
border-radius: 5px;
background-color: hotpink;
color: white;
cursor: pointer;
}
/* 默认 */
.tile,.showed,.boom{
width: 49px;
height: 49px;
border: 1px solid ;
float: left;
cursor: pointer;
}
.tile{
background: url(./img/ba.png);
}
/* 已点击 */
.showed{
background-color: #C3CEE5;
line-height: 49px;
}
/* 雷 */
.boom{
background: #C3CEE5 url(./img/Minesmall.png);
}
.current{
background: url(./img/baq.png);
}
/* 小红旗 */
.tag{
/* 添加多个背景图片,前面的优先 */
background: url(./img/hq.png),url(./img/ba.png);
}
JavaScript
function mineClearance(row, column, mine_num) {
// 属性配置
var settings = {
// 行
row: row,
// 列
column: column,
// 雷
mine_num: mine_num,
// 盒子ID
obj: 'content',
// 生成的每一个小div
tiles: [],
// 表示是否是第一次点击
flag: true,
// 保存某个元素的周边八个元素
arr: []
};
// 创建画板
buildTiles();
// 绑定事件
event();
/**
* 创建画板的函数
*/
function buildTiles() {
// 获取画板对象
var obj = document.getElementById(settings.obj);
// 每个小div大小是51*51
// 所以 画板大小为 51*column , 51*row
obj.style.width = 51 * settings.column + 'px';
obj.style.height = 51 * settings.row + "px";
// 生成小div
// 对div添加索引,0开始,一次递增,方便获取周边八个div
var indexOfdiv = 0;
for (let i = 0; i < settings.row; i++) {
for (let j = 0; j < settings.column; j++) {
// 创建div
var tile = document.createElement('div');
// 设置默认 class
tile.className = 'tile';
// 添加索引
tile.index = indexOfdiv++;
// 添加自定义属性,当mine值为0时,说明不是雷
tile.setAttribute('mine', 0);
// 保存到数组中
settings.tiles.push(tile);
// 添加到画板中
obj.appendChild(tile);
}
}
}
/**
* 绑定事件的函数
*/
function event() {
// 创建画板对象
var obj = document.getElementById(settings.obj);
// 对画板绑定事件,通过事件源找到每一个小div
// 移入
obj.onmousemove = function (e) {
// 判断事件源是否是可以点击的小div
// console.log(e.target.className, e.target.className == 'tile');
if (e.target.className == 'tile') {
e.target.className = 'tile current';
//移入音乐
var mp3move=new Audio("./mp3/move.mp3");
mp3move.play();
}
}
// 移出
obj.onmouseout = function (e) {
// 判断事件源是否是可以点击的小div
if (e.target.classList.contains('current')) {
e.target.className = e.target.className.replace('current', '').trim();
}
}
// 右键标记小红旗
obj.oncontextmenu = function (e) {
// 判断事件源是否是可以点击的小div
if (!e.target.classList.contains('showed') && !e.target.classList.contains('boom')) {
if (e.target.classList.contains('tag')) {
e.target.className = e.target.className.replace('tag', '').trim();
} else {
// 注意空格,多类名以空格隔开
e.target.className += ' tag';
}
}
// 清除浏览器默认右键事件
return false;
}
// 点击事件
obj.onclick = function (e) {
//点击音乐
var mp3click=new Audio("./mp3/click.mp3");
mp3click.play();
// 点击的div索引
var index = e.target.index;
// 点击的div对象
var obj = e.target;
// console.log(index);
// 判断是否添加小红旗
if (e.target.classList.contains('tag')) {
alert('有小红旗不能点击');
return;
}
// 判断是不是第一次点击
if (settings.flag) {
// 设置为false,下次点击不再初始化
settings.flag = false;
// 如果是第一次点击就初始化雷
for (let i = 0; i < settings.mine_num; i++) {
// 随机数 : 0~99之间
// 结果 = 向下取整(随机数*(最大值-最小值+1)+最小值)
var randomNum = Math.floor(Math.random() * settings.tiles.length);
// 保证第一次点击的一定不是雷
// if(randomNum == index){
// i--;
// continue;
// }
// 获取对应索引的div对象,判断mine的值是否是0
var divObj = settings.tiles[randomNum];
// 如果是0 则设置为1
if (divObj.getAttribute('mine') == 0) {
divObj.setAttribute('mine', 1);
} else {
// 如果是1 说明已经设置过了,需要i
i--;
}
}
// 设置周围几个雷
showValue();
}
// 初始化完成,判断点击的是不是雷等
if (obj.getAttribute('mine') == 0) {
// 设置为已点击状态
obj.className = 'showed';
// 设置周围 雷的个数
obj.innerHTML = obj.getAttribute('value') == 0 ? '' : obj.getAttribute('value');
// 显示周围的div,扩散
showAll(index);
}
// 判断游戏是否结束
// 如果结束了就显示所有 div信息
var isOver = over(obj);
if (isOver) {
// 到这里说明游戏结束
last();
}
}
}
/**
* 判断游戏是否结束,参数为点击的对象
* @param {*} obj
*/
function over(obj) {
// 默认没有结束,true表示结束
var flag = false;
// 获取所有已点击的
var showed = document.getElementsByClassName('showed');
// 失败 : 判断点击的是不是雷
if (obj.getAttribute('mine') == 1) {
flag = true;
//失败音乐
var mp3fail=new Audio("./mp3/gameover.mp3");
mp3fail.play();
isstopmp3a=1;
alert('很遗憾...啥也不是');
} else if (showed.length + settings.mine_num == settings.tiles.length) {
// 胜利 : 已点击的div+雷的个数 = 总数
flag = true;
alert('一不小心就让你赢了 ');
}
return flag;
}
/**
* 游戏结束后,重置div,把雷和不是雷都显示出来
*/
function last() {
// 遍历所有div , tiles
for (let i = 0; i < settings.tiles.length; i++) {
// 判断mine 是否是1
if (settings.tiles[i].getAttribute('mine') == 1) {
// 如果是1 ,class设置为boom
settings.tiles[i].className = 'boom';
} else {
// 如果不是1 , class设置为 showed
settings.tiles[i].className = 'showed';
}
// 显示周围雷的个数
if (settings.tiles[i].className != 'boom') {
settings.tiles[i].innerHTML = settings.tiles[i].getAttribute('value') == 0 ? '' : settings.tiles[i].getAttribute('value');
}
}
// 取消点击事件
document.getElementById(settings.obj).onclick=null;
}
/**
* 显示周围多少雷,递归扩散
*
* 参数是当前的div索引
*
* @param {*} index
*/
function showAll(index) {
// 1 判断当前是否是雷
// 2 如果周围八个中 有class为showed 说明不是雷
// 3 判断该对象周围是否有雷(value属性是否等于0)
// 4 如果value为0,则获取周围八个元素,然后再递归判断周围八个元素的周围元素是否有雷
if (settings.tiles[index].className == 'showed' && settings.tiles[index].getAttribute('value') == 0) {
// 获取周围八个元素
store(index);
// 把周围八个保存为局部变量,否则获取周围八个元素的时候会重新对settings.arr重新赋值
var arr2 = settings.arr;
for (let i = 0; i < arr2.length; i++) {
// 判断周围元素是否为未点击状态
if (arr2[i].className != 'showed') {
// 判断是否周围没有雷
if (arr2[i].getAttribute('value') == 0) {
// 如果没有 设置为显示状态
arr2[i].className = 'showed';
// 并且递归获取该元素周围八个的情况
showAll(arr2[i].index);
} else {
// 到这里说明周围有雷
// 设置为显示状态
arr2[i].className = 'showed';
// 设置周围雷的个数
arr2[i].innerHTML = arr2[i].getAttribute('value');
}
}
}
}
}
/**
* 设置value属性,保存的是周边八个div中有几个雷
*/
function showValue() {
// 保存周围雷的个数
var count = 0;
// 0 遍历所有元素
for (let i = 0; i < settings.tiles.length; i++) {
// 判断是否是雷,因为雷不需要设置周围雷的个数
if (settings.tiles[i].getAttribute('mine') == 1) {
continue;
}
// 1 获取每一个周边八个元素
store(settings.tiles[i].index);
// 2 判断每个元素的mine属性是否是1
// 遍历周边八个元素有几个雷
for (let j = 0; j < settings.arr.length; j++) {
if (settings.arr[j].getAttribute('mine') == 1) {
// 3 统计有多少个雷
count++;
}
}
// 4 设置到该标签中 value 表示周围雷的个数
settings.tiles[i].setAttribute('value', count);
// 重新把count清除,然后重新计算
count = 0;
}
}
/**
* 获取并存储指定元素周围的八个元素
*
* 一维数组实现方式
*
* index 就是该元素的索引
* @param {*} index
*/
function store(index) {
// 存储列
var column = settings.column;
// 清空原来周边八个的数组
settings.arr = [];
// 上 : index - 列 , 结果如果小于0 说明没有上面的(比如第一排)
if (index - column >= 0) {
settings.arr.push(settings.tiles[index - column]);
}
// 下 : index + 列 , 结果如果大于等于长度,说明没有(比如最后一排)
if (index + column < settings.tiles.length) {
settings.arr.push(settings.tiles[index + column]);
}
// 左 : index % 列 取余,结果为0 说明没有左,比如 最左边一列,如果不是0,则为 index-1
if (index % column != 0) {
settings.arr.push(settings.tiles[index - 1]);
}
// 右 : (index + 1)%列 取余,结果为0,说明没有有,比如最右边一列
if ((index + 1) % column != 0) {
settings.arr.push(settings.tiles[index + 1]);
}
// 右上 : (index-列+1)%列 取余,结果为0说明没有右上(比如最后一列) 并且 index - 列 +1 , 结果如果小于0 说明没有右上面的(比如第一排)
if ((index + 1) % column != 0 && index - column >= 0) {
settings.arr.push(settings.tiles[index - column + 1]);
}
// 左上 : index % 列 取余,结果为0 说明没有左上,比如 最左边一列,并且 index - 列 -1 , 结果如果小于0 说明没有左上面的(比如第一排)
if (index % column != 0 && index - column >= 0) {
settings.arr.push(settings.tiles[index - column - 1]);
}
// 右下 : 右 && 下,通过上面规则,右下,就是符合右的条件也符合下的条件
if ((index + 1) % column != 0 && index + column < settings.tiles.length) {
// index + 列 + 1
settings.arr.push(settings.tiles[index + column + 1]);
}
// 左下 : 左 && 下
// index + 列 - 1
if (index % column != 0 && index + column < settings.tiles.length) {
// index + 列 + 1
settings.arr.push(settings.tiles[index + column - 1]);
}
}
}
--------------------------------------------------------------------------------------------------------------------------------
jQuery介绍
(1)、JavaScript与jQuery比较
js: 1、入口函数只有一个,window.onload
- 浏览器兼容性:非常令人头疼,比如textContent虽然作为标准方法但是只支持IE8+以上的浏览器
- DOM错综复杂,实现简单的效果很麻烦
- 代码容错性差,出错后导致后面的代码不执行
jQuery: 1、市场占有率稳步上升,代码比较少,功能强大
2、DOM比较强大,事件处理,完全解决了浏览器的兼容性问题
3、ajax操作(比较好)
(2)、什么是jQuery
1、jQuery是一个JavaScript函数库。
2、jQuery是一个轻量级的"写的少,做的多"的JavaScript库。
3、jQuery库包含以下功能:HTML 元素选取、HTML 元素操作、CSS 操作、HTML 事件函数、JavaScript 特效和HTML DOM 遍历和修改。
(3)、为什么使用jQuery
1、目前网络上有大量开源的 JS 库, 但是 jQuery 是目前最流行的 JS 库,而且提供了大量的扩展。
2、很多大公司都在使用 jQuery, 例如:Google、Microsoft、IBM、Netflix。
3、目前jQuery兼容于所有主流浏览器, 包括Internet Explorer 6!
jQuery安装
1、从 jquery.com 下载 jQuery 库
jQuery 库是一个 JavaScript 文件,您可以使用 HTML 的 <script> 标签引用它:
<head>
<script src="jquery-1.10.2.min.js"></script>
</head>
2、从 CDN 中载入 jQuery, 如从 Google 中加载 jQuery
<head>
<script src="https://cdn.staticfile.org/jquery/1.10.2/jquery.min.js"> </script>
</head>
jQuery语法
(1)、基础语法
1、美元符号定义 jQuery
2、选择符(selector)"查询"和"查找" HTML 元素
3、jQuery 的 action() 执行对元素的操作。
(2)、实例
1、您也许已经注意到在我们的实例中的所有 jQuery 函数位于一个 document ready 函数中:
$(document).ready(function(){
// 开始写 jQuery 代码... }
);
2、简洁写法(与以上写法效果相同):
$(function(){
// 开始写 jQuery 代码...
})
(3)了解jQuery的$符号
$是什么
其实$就是一个函数:$();参数不一样,功能不一样
$常用的几种情况:
$(function() {});//参数是function,说明是入口函数
$(“#btnSetConent”);//参数是字符串,并且以#开头,是一个标签选择,查找id=“btnSetContent”的元素
$(“div”);//查找所有的div元素
$(document).ready(funciton(){})//将document转换成jQuery对象
(4)、jQuery 入口函数与 JavaScript 入口函数的区别
jQuery 的入口函数是在 html 所有标签(DOM)都加载之后,就会去执行。
JavaScript 的 window.onload 事件是等到所有内容,包括外部图片之类的文件加载完后,才会执行。
- JQuery选择器
(1)、什么是jQuery选择器
1、jQuery 选择器允许您对 HTML 元素组或单个元素进行操作。
2、jQuery选择器是jQuery为我们提供的一组方法,让我们更加方便的获取到页面中的元素。注意:jQuery选择器返回的是jQuery对象。
3、jQuery 选择器基于元素的 id、类、类型、属性、属性值等"查找"(或选择)HTML 元素。 它基于已经存在的 CSS 选择器,除此之外,它还有一些自定义的选择器。
4、jQuery 中所有选择器都以美元符号开头:$()。
(2)、基本选择器
名称
用法
描述
ID选择器
$(“#id”);
获取指定ID的元素
类选择器
$(“.class”);
获取同一类class的元素
标签选择器
$(“div”);
获取同一类标签的所有元素
并集选择器
$(“div,p,li”);
使用逗号分隔,只要符合条件之一就可。获取所有的div、p、li元素
交集选择器(标签指定式选择器)
$(“div.redClass”);
注意选择器1和选择器2之间没有空格,class为redClass的div元素,注意区分后代选择器。
总结:和css选择器的用法一模一样
(3)、层级选择器
名称
用法
描述
子代选择器
$(“ul>li”);
使用>号,获取儿子层级的元素,注意,并不会获取孙子层级的元素
后代选择器
$(“ul li”);
使用空格,代表后代选择器,获取ul下的所有li元素,包括孙子等
总结:跟CSS的选择器一模一样。
(4)、过滤选择器
用法
描述
:eq(index)
$(“li:eq(2)”).css(“color”, ”red”);
获取到的li元素中,选择索引号为2的元素,索引号index从0开始。
:odd
$(“li:odd”).css(“color”, ”red”);
获取到的li元素中,选择索引号为奇数的元素
:even
$(“li:even”).css(“color”, ”red”);
获取到的li元素中,选择索引号为偶数的元素
总结:这类选择器都带冒号。
(5)、筛选选择器(方法)
用法
说明
children(selector)
$(“ul”).children(“li”)
相当于$(“ul>li”),子类选择器
find(selector)
$(“ul”).find(“li”);
相当于$(“ul li”),后代选择器
siblings(selector)
$(“#first”).siblings(“li”);
查找兄弟节点,不包括自己本身。
parent()
$(“#first”).parent();
查找父亲
eq(index)
$(“li”).eq(2);
相当于$(“li:eq(2)”),index从0开始
next()
$(“li”).next()
找下一个兄弟
prev()
$(“li”).prev()
找上一次兄弟
Index()
$(“li”).index()
获取当前的位置(索引)
not()
$("p").not(".intro")
返回不带有类名 "intro" 的所有 <p> 元素
总结:筛选选择器的功能与过滤选择器有点类似,但是用法不一样,筛选选择器主要是方法。
jQuery事件
(1)、什么是事件
1、页面对不同访问者的响应叫做事件。
2、实例:在元素上移动鼠标、选取单选按钮、点击元素
(1)、事件语法
1、单击事件
$("p").click(function(){
// 动作触发后执行的代码!!
});
2、双击事件
$("p").dblclick(function(){
$(this).hide();
})
3、鼠标进入
$("#p1").mouseenter(function(){
alert('您的鼠标移到了 id="p1" 的元素上!');
});
4、鼠标离开
$("#p1").mouseleave(function(){
alert("再见,您的鼠标离开了该段落。");
});
5、获取焦点
$("input").focus(function(){
$(this).css("background-color","#cccccc");
});
6、失去焦点
$("input").blur(function(){
$(this).css("background-color","#ffffff");
});