一、GIF图展示:
二、实现功能需要的js技术栈
1.一维数组和二维数组
2.使用js选择器选择DOM元素并操作DOM元素
3.循环,函数,使用js修改DOM样式
三、实现思路
1.棋盘的初始化
定义一个容器作为棋盘,使用二维数组映射棋盘,再使用一个数组保存图片地址,二维数组的每个数由随机数产生,随机数的范围是0~存放图片数组的长度-1。然后通过初始化函数遍历所有格子,把格子里面的数字对应为图片数组,再通过操作DOM元素修改图片的地址渲染整个数组。
初始化HTML代码
<!-- 棋盘容器 -->
<div id="game">
</div>
棋盘基本样式CSS
/* 消消乐容器宽高 */
#game {
width: 500px;
height: 500px;
margin: 50px auto 0;
}
/* 消消乐每个格子 */
#game li {
float: left;
width: 46px;
height: 46px;
border: 2px solid skyblue;
overflow: hidden;
}
初始化棋盘部分代码
//创建一个二维数组作为棋盘的映射
var board = []
//判断当前所放容器能放几个图标
var container = document.querySelector("#game")
var containerWidth = container.offsetWidth
var containerHeight = container.offsetHeight
// ul的个数等于容器宽度等于二维数组的行
var countLine = containerHeight / 50
var countCol = containerWidth / 50
//图片列表(消除的元素)
var imgList = ["./img/1.png", "./img/2.png", "./img/3.png", "./img/4.png", "./img/5.png"]
//初始化数组 建立结构
for (let i = 0; i < countLine; i++) {
var temp = []
board.push(temp)
for (var j = 0; j < countCol; j++) {
board[i][j] = 0
}
}
//渲染棋盘结构
for (let i = 0; i < board.length; i++) {
var ul = document.createElement("ul")
//ul对应二维数组的行 设置索引
ul.setAttribute("index", i)
for (let j = 0; j < board[0].length; j++) {
var li = document.createElement("li")
//ul对应二维数组的列
li.setAttribute("index", j)
var img = document.createElement("img")
var ramdom = Math.floor(Math.random() * imgList.length)
board[i][j] = ramdom
li.appendChild(img)
ul.appendChild(li)
}
container.appendChild(ul)
}
//更新棋盘逻辑(遍历棋盘数组)渲染格子内容
function updateBoard() {
removeAroundMark()
for (let i = 0; i < board.length; i++) {
for (let j = 0; j < board[0].length; j++) {
var img = document.querySelectorAll("#game ul")[i].children[j].children[0]
img.style.animation = "none"
if (img.className == "alreadySet") {
var randomIndex = Math.floor(Math.random() * imgList.length)
board[i][j] = randomIndex
img.className = "notSet"
}
img.src = imgList[board[i][j]]
}
}
}
//调用渲染格子内容函数
updateBoard()
2.点击消除逻辑
给整个棋盘添加点击事件, 当点击棋盘的某个格子的时候,拿到此格子的元素,通过getAttribute()方法拿到该格子在棋盘的位置,也就是在棋盘上二维数组的位置。通过拿到该格子的坐标访问二维数组,进入判断函数:对其上下左右进行判断,如果y轴(上下)或者x轴(左右),有两个以及两个以上的数字,则把上下左右的相同数量送入消除函数。
消除函数里面:拿到点击的坐标和相同的数量的个数,通过循环遍历,拿到这些要被消除的数组索引,并且在DOM棋盘上进行标记,再次进入判断函数,直到上下左右构不成消除的条件,最后更新棋盘,就完成了一个循环。
JS部分代码
//判断点击天气上下是否为3个以及3个以上
function judgeY(x, y) {
var top = x - 1
var bottom = x + 1
var countTop = 0
var countBottom = 0
// 寻找上面一共有几个并计数
if (top >= 0) {
while (board[x][y] == board[top][y]) {
countTop++
top--
if (top < 0) {
break
}
}
}
//寻找下面有几个并计数
if (bottom < board.length) {
while (board[x][y] == board[bottom][y]) {
countBottom++
bottom++
if (bottom > board.length - 1) {
break
}
}
}
//如果上面加上面相同的超过3个 则执行消除操作
if (countBottom + countTop >= 2) {
//消除
removeItem("x", x, y, countTop, countBottom)
return 1;
}
}
//判断点击左右是否为3个或者三个以上
function judgeX(x, y) {
var left = y - 1
var right = y + 1
var countLeft = 0
var countRight = 0
if (left >= 0) {
while (board[x][y] == board[x][left]) {
left--
countLeft++
if (left < 0) {
break
}
}
}
if (right <= board[0].length) {
while (board[x][y] == board[x][right]) {
right++
countRight++
if (right > board[0].length) {
break
}
}
}
if (countLeft + countRight >= 2) {
//消除
removeItem("y", x, y, countLeft, countRight)
return 1;
}
}
//消除函数
//判断消除的是横向还是纵向
function removeItem(direction, x, y, min, max) {
//纵向消除逻辑
if (direction == "x") {
console.log(x, y, min, max);
for (let i = x - min; i <= x + max; i++) {
var img = document.querySelectorAll("#game ul")[i].children[y].children[0]
if (img.className == "alreadySet") {
continue
} else {
img.className = "alreadySet"
addTargetAnima(i, y)
//再次判断要被消除的元素周围是否存在可消除条件
rewriteYX(i, y)
}
}
}
//横向消除逻辑
if (direction == "y") {
for (let i = y - min; i <= y + max; i++) {
//再次判断要被消除的元素周围是否存在可消除条件
judgeY(x, i)
var img = document.querySelectorAll("#game ul")[x].children[i].children[0]
if (img.className == "alreadySet") {
continue
}
img.className = "alreadySet"
addTargetAnima(x, i)
}
}
}
//再次判断纵向消除时 左右消除的逻辑
function rewriteYX(x, y) {
var left = y - 1
var right = y + 1
var countLeft = 0
var countRight = 0
if (left >= 0) {
while (board[x][y] == board[x][left]) {
left--
countLeft++
if (left < 0) {
break
}
}
}
if (right <= board[0].length) {
while (board[x][y] == board[x][right]) {
right++
countRight++
if (right > board[0].length) {
break
}
}
}
if (countLeft + countRight >= 2) {
//消除
for (let i = y - countLeft; i <= y + countRight; i++) {
var img = document.querySelectorAll("#game ul")[x].children[i].children[0]
if (img.className == "alreadySet") {
continue
} else {
img.className = "alreadySet"
addTargetAnima(x, i)
}
}
}
}
3.上下/左右交换
判断逻辑
点击棋盘的时候把点击的位置送到判断函数里面,如果判断函数有返回值则优先执行消除逻辑,否则执行交换逻辑。
交换逻辑
1.不能交换:
首先把点击的第一个坐标的周围使用标记函数对齐周围进行标记,如果点击第二个位置的坐标没有此标记,则此次交换不成立,再判断此次交换以后是否能消除,如果不能消除,此次交换不成立 。
2.可以交换:
判断 为上下交换还是左右交换,进入对应的逻辑进行增加该方向消除动画,然后把交换以后的两个坐标放进判断函数进行消除。
JS部分代码
//判断是否有上下左右属性如果有的话交换
var res = document.querySelectorAll("#game ul")[swapTemp[1][0]].children[swapTemp[1][1]].getAttribute(
"v-brother")
if (res) {
//再交换之前判断交换后是否能消除 如果交换后不能消除则不交换
var one = [swapTemp[0][0], swapTemp[0][1]]
var two = [swapTemp[1][0], swapTemp[1][1]]
var temp = 0
//交换二维数组
temp = board[one[0]][one[1]]
board[one[0]][one[1]] = board[two[0]][two[1]]
board[two[0]][two[1]] = temp
change = true
if (!(judgeX(one[0], one[1]) || judgeY(one[0], one[1]) || judgeX(two[0], two[1]) || judgeY(two[0], two[
1]))) {
// 不能交换 清除高亮
document.querySelectorAll("#game ul")[swapTemp[0][0]].children[swapTemp[0][1]].className = "none"
document.querySelectorAll("#game ul")[swapTemp[1][0]].children[swapTemp[1][1]].className = "none"
//不能交换就把交换的数组交换回来
temp = board[one[0]][one[1]]
board[one[0]][one[1]] = board[two[0]][two[1]]
board[two[0]][two[1]] = temp
swapTemp = []
return 0;
}
}
if (res) {
//判断是上下还是左右
if (swapTemp[0][0] == swapTemp[1][0]) {
var imgLeft = document.querySelectorAll("#game ul")[swapTemp[0][0]].children[swapTemp[0][1]]
.children[0]
var imgRight = document.querySelectorAll("#game ul")[swapTemp[1][0]].children[swapTemp[1][1]]
.children[0]
imgLeft.style.animation = "none"
imgRight.style.animation = "none"
var tempSrc = imgLeft.src
imgLeft.src = imgRight.src
imgRight.src = tempSrc
//交换图片
var re = /\d.png/
var imgLeftSrc = "./img/" + imgLeft.src.match(re)[0]
var imgRightSrc = "./img/" + imgRight.src.match(re)[0]
var indexL = imgList.indexOf(imgLeftSrc)
var indexR = imgList.indexOf(imgRightSrc)
//左右交换动画 并标记是左右动画 底下不在执行消除动画
imgRight.setAttribute("animateType", "line")
imgLeft.setAttribute("animateType", "line")
//判断哪个是左
var animateLeft;
var animateRight;
if (swapTemp[0][1] < swapTemp[1][1]) {
animateRight = imgRight
animateLeft = imgLeft
} else {
animateRight = imgLeft
animateLeft = imgRight
}
animateLeft.style.animation = "lineLeft 0.5s normal linear"
animateRight.style.animation = "lineRight 0.5s normal linear"
board[swapTemp[0][0]][swapTemp[0][1]] = indexL
board[swapTemp[1][0]][swapTemp[1][1]] = indexR
console.log("左右交换");
//交换完成以后送去消除
judgeX(swapTemp[1][0], swapTemp[1][1])
judgeX(swapTemp[0][0], swapTemp[0][1])
judgeY(swapTemp[0][0], swapTemp[0][1])
judgeY(swapTemp[1][0], swapTemp[1][1])
} else {
var imgTop = document.querySelectorAll("#game ul")[swapTemp[0][0]].children[swapTemp[0][1]]
.children[0]
var imgBottom = document.querySelectorAll("#game ul")[swapTemp[1][0]].children[swapTemp[1][1]]
.children[0]
imgTop.style.animation = "none"
imgBottom.style.animation = "none"
var tempSrc = imgTop.src
imgTop.src = imgBottom.src
imgBottom.src = tempSrc
var re = /\d.png/
var imgTopSrc = "./img/" + imgTop.src.match(re)[0]
var imgBottomSrc = "./img/" + imgBottom.src.match(re)[0]
var indexT = imgList.indexOf(imgTopSrc)
var indexB = imgList.indexOf(imgBottomSrc)
//列交换动画
var animateTop;
var animateBottom;
if (swapTemp[0][0] < swapTemp[1][0]) {
animateTop = imgTop
animateBottom = imgBottom
} else {
animateTop = imgBottom
animateBottom = imgTop
}
animateTop.style.animation = "colTop 0.5s normal linear"
animateBottom.style.animation = "colBottom 0.5s normal linear"
board[swapTemp[0][0]][swapTemp[0][1]] = indexT
board[swapTemp[1][0]][swapTemp[1][1]] = indexB
judgeX(swapTemp[1][0], swapTemp[1][1])
judgeX(swapTemp[0][0], swapTemp[0][1])
judgeY(swapTemp[0][0], swapTemp[0][1])
judgeY(swapTemp[1][0], swapTemp[1][1])
}
}
//交换完把高亮样式删除
document.querySelectorAll("#game ul")[swapTemp[0][0]].children[swapTemp[0][1]].className = "none"
document.querySelectorAll("#game ul")[swapTemp[1][0]].children[swapTemp[1][1]].className = "none"
//删除所有标记
removeAroundMark()
swapTemp = []
//标记周围
function markAround(x, y, top, bottom, left, right) {
document.querySelectorAll("#game ul")[x].children[y].setAttribute("v-brother", "brother")
if (top >= 0) {
document.querySelectorAll("#game ul")[top].children[y].setAttribute("v-brother", "brother")
}
if (bottom < board.length) {
document.querySelectorAll("#game ul")[bottom].children[y].setAttribute("v-brother", "brother")
}
if (left >= 0) {
document.querySelectorAll("#game ul")[x].children[left].setAttribute("v-brother", "brother")
}
if (right < board.length) {
document.querySelectorAll("#game ul")[x].children[right].setAttribute("v-brother", "brother")
}
}
//清楚周围标记
function removeAroundMark() {
for (let i = 0; i < board.length; i++) {
for (var j = 0; j < board[0].length; j++) {
document.querySelectorAll("#game ul")[i].children[j].removeAttribute("v-brother")
}
}
}