有一个网格,其中有一个谜题,可以通过拖放来交换方块,以便重新创建显示在网格旁边/下方的图像。但是,当用户快速拖放一个方块时,网格会被打乱,并且某些方块最终会出现在网格之外。然而游戏仍然有效,用户仍然可以将网格中的方块与网格外的方块交换。网格外的正方形原本应该在的地方只有空白。
我尝试过使用不同的拖放方法,但尽管如此,这个错误仍然出现,所以问题不在于拖放方法。
我该如何解决这个问题?
JS 小提琴:https://jsfiddle.net/c5ayk3re/
let images = [{
src: "https://picsum.photos/200",
title: "the first image"
},
{
src: "https://picsum.photos/200",
title: "the second image"
},
{
src: "https://picsum.photos/200",
title: "the woffle image"
},
{
src: "https://picsum.photos/200",
title: "the puzzel image"
},
{
src: "https://picsum.photos/200",
title: "the lone image"
},
{
src: "https://picsum.photos/200",
title: "the noone image"
},
{
src: "https://picsum.photos/200",
title: "the ,mdp image"
},
{
src: "https://picsum.photos/200",
title: "the dfkg image"
},
{
src: "https://picsum.photos/200",
title: "the title image"
},
];
let dragindex = 0;
let steps = 0;
let draged = null;
let sortUl = document.querySelector(".sort");
let sortLi;
let actImg = document.querySelector(".act-img img");
let levels = Array.from(document.querySelectorAll(".show span"));
let start = document.querySelector(".show button");
// on start game
// handle active function
let handleActive = function(span) {
span.currentTarget.parentElement
.querySelectorAll(".active")
.forEach(ele => {
ele.classList.remove("active");
});
span.currentTarget.classList.add("active");
};
levels.forEach(level => {
level.addEventListener("click", e => {
handleActive(e);
window.sessionStorage.setItem("level", e.currentTarget.dataset.mode);
window.sessionStorage.setItem("level1", e.currentTarget.textContent);
});
});
let unshuffled = [];
let shuffled = [];
let arr = [];
let sizeUi = 400;
let actLevel = document.querySelector(".act-level span");
start.addEventListener("click", () => {
document.querySelector(".show").style.left = "-100%";
actLevel.textContent = window.sessionStorage.getItem("level1");
const randomImg = images[Math.floor(Math.random() * images.length)].src;
actImg.src = randomImg;
let level = window.sessionStorage.getItem("level");
if (!level) level = 3;
let size = level * 100;
let percent = 100 / (level - 1);
unshuffled = [];
arr = [];
for (i = 0; i < level * level; i++) {
let x = percent * (i % level);
let y = percent * Math.floor(i / level);
const li = document.createElement("li");
li.style.cssText = "background-image: url(" + randomImg + ");";
li.setAttribute("data-num", i);
li.setAttribute("draggable", "true");
li.setAttribute("id", `id-${i}`);
li.style.backgroundSize = size + "%";
li.style.backgroundPosition = x + "%" + y + "%";
if (window.innerWidth < 315) {
li.style.width = 225 / level + "px";
li.style.height = 225 / level + "px";
} else if (window.innerWidth < 375) {
li.style.width = 250 / level + "px";
li.style.height = 250 / level + "px";
} else if (window.innerWidth < 450) {
li.style.width = 300 / level + "px";
li.style.height = 300 / level + "px";
} else if (window.innerWidth < 550) {
li.style.width = 350 / level + "px";
li.style.height = 350 / level + "px";
} else {
li.style.width = 400 / level + "px";
li.style.height = 400 / level + "px";
}
unshuffled.push(li);
arr.push(li);
}
for (let i = unshuffled.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
const temp = unshuffled[i];
unshuffled[i] = unshuffled[j];
unshuffled[j] = temp;
}
unshuffled.forEach(e => {
sortUl.appendChild(e);
});
});
// let act_arr = Array.from(document.querySelectorAll(".sort li"));
/////////////////////////////////////
sortUl.addEventListener("dragstart", dragstart);
sortUl.addEventListener("dragover", dragover);
sortUl.addEventListener("drop", drop);
function dragstart(e) {
e.dataTransfer.setData("text/plain", e.target.id);
}
function dragover(e) {
e.preventDefault();
}
function drop(e) {
e.preventDefault();
const clone = e.target.cloneNode(true);
let data = e.dataTransfer.getData("text/plain");
if (document.getElementById(data)) {
if (clone.id !== data) {
let nodelist = document.querySelector(".sort").childNodes;
for (let i = 0; i < nodelist.length; i++) {
if (nodelist[i].id === data) {
dragindex = i;
}
}
const targetElement = document.getElementById(data);
if (targetElement) {
document
.querySelector(".sort")
.replaceChild(document.getElementById(data), e.target);
document
.querySelector(".sort")
.insertBefore(
clone,
document.querySelector(".sort").childNodes[dragindex],
);
}
}
}
}
/////////////////////////////////
let count = document.querySelector(".count");
let win = document.querySelector(".body .win");
const playMore = document.querySelector(".win span");
sortUl.addEventListener("dragend", e => {
const actElements = Array.from(document.querySelectorAll(".sort li"));
const correctOrder = Array.from(arr).map(piece => piece.id);
if (actElements.every((piece, index) => piece.id === correctOrder[index])) {
win.style.left = "15%";
win.style.transform = "translate(-50%)";
document.querySelector(".win .count").textContent = steps;
} else {
steps++;
count.textContent = steps;
}
});
playMore.addEventListener("click", () => {
document.querySelector(".show").style.left = "0";
win.style.left = "-100%";
document.querySelectorAll(".sort li").forEach(e => {
e.remove();
});
});
document.getElementById("exit").onclick = () => {
document.querySelectorAll(".sort li").forEach(e => {
e.remove();
});
document.querySelector(".show").style.left = "0";
steps = 0;
count.textContent = "0";
};
@import url("https://fonts.googleapis.com/css2?family=Open+Sans:wght@600&family=Oswald&family=PT+Sans+Narrow&family=Roboto+Slab&display=swap");
@font-face {
font-family: LapsusPro;
src: url('LapsusPro-Bold.otf');
}
* {
font-family: LapsusPro, sans-serif;
}
body {
margin: 0;
padding: 0;
}
.container {
width: 90%;
padding: 2rem 1rem;
height: 100%;
margin: auto;
}
.head {
text-align: center;
}
.head h1 {
background-color: #2196f3;
padding: 10px;
}
.head p {
font-size: 20px;
margin-top: -6px;
}
.body {
display: flex;
gap: 3rem;
background: #03a9f4;
padding: 10px;
border-radius: 10px;
justify-content: center;
overflow: hidden;
transition: 0.5s;
z-index: 1;
text-align: center;
}
@media only screen and (max-width: 900px) {
.body {
display: grid;
grid-template-columns: 1fr;
align-items: center;
gap: 1rem;
}
}
.body .show {
text-align: center;
position: absolute;
width: 100%;
height: 100%;
background-color: #607d8b;
border-radius: 8px;
transition: all 0.5s;
left: 0;
z-index: 2;
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
gap: 2rem;
}
.body .show h2 {
color: #fff;
font-style: italic;
font-size: 30px;
border-bottom: 2px solid #3333;
margin: 0;
}
.body .show span {
margin: 0;
font-size: 32px;
text-transform: capitalize;
color: #fff;
display: block;
width: fit-content;
height: fit-content;
background-color: #03a9f4;
padding: 5px 16px;
border-radius: 7px;
cursor: pointer;
opacity: 0.3;
transition: all 0.5s;
}
.body .show span.active,
.body .show span:hover {
opacity: 1;
}
.body .show button {
font-size: 30px;
padding: 5px 12px;
background-color: #3f51b5;
color: #fff;
font-style: oblique;
border: none;
border-radius: 26px;
cursor: pointer;
margin-top: 0.5rem;
}
.game-page {
display: flex;
justify-content: center;
align-items: center;
flex-direction: column
}
.body ul {
/* flex: 1; */
border: 1px solid #333;
border-radius: 3px;
width: 400px;
height: 400px;
padding-left: 0;
}
@media only screen and (max-width: 550px) {
.body ul {
width: 350px;
height: 350px;
}
}
@media only screen and (max-width: 450px) {
.body ul {
width: 300px;
height: 300px;
}
}
@media only screen and (max-width: 375px) {
.body ul {
width: 250px;
height: 250px;
}
}
@media only screen and (max-width: 315px) {
.body ul {
width: 225px;
height: 225px;
}
}
.body ul li {
list-style-type: none;
padding: 0;
margin: 0;
float: left;
cursor: pointer;
}
/* .body ul li:hover {
opacity: 0.5;
} */
.body .act-img {
width: 250px;
height: auto;
}
.body .act-img img {
max-width: 100%;
}
.body .steps {
display: inline-block;
font-size: 23px;
margin: 8px 0;
}
.body .steps+div {
display: inline-block;
font-size: 20px;
}
.body .act-level {
margin: 20px 0;
font-size: 24px;
text-transform: capitalize;
display: flex;
justify-content: space-between;
flex-direction: column;
}
.body .act-level button {
padding: 5px 12px;
font-size: 20px;
border-radius: 20px;
border: none;
cursor: pointer;
background-color: #607d8b;
color: #fff;
text-transform: capitalize;
margin: 20px 0 0 0;
}
.body .win {
position: absolute;
width: 70%;
height: 70%;
background-color: #2196f3;
border-radius: 10px;
color: #fff;
font-size: 20px;
left: -100%;
top: 15%;
transform: none;
text-align: center;
padding: 20px;
transition: 0.5s;
opacity: 1;
z-index: 5;
}
.body .win h2 {
text-transform: capitalize;
}
.body .win .steps {
text-transform: capitalize;
}
.body .win span {
display: block;
background-color: #607d8b;
width: fit-content;
padding: 5px 10px;
border-radius: 6px;
margin: auto;
cursor: pointer;
}
<div class="container">
<div class="head">
<h1>PUZZLE</h1>
<p> Drag each piece to match the image below</p>
</div>
<div class="body" style="position: relative">
<div class="show">
<h2>choose your game mode</h2>
<span class="active" data-mode="3">easy</span>
<span data-mode="4">medium</span>
<span data-mode="5">hard</span>
<span data-mode="6"> very hard</span>
<button>start game</button>
</div>
<div class="game-page">
<ul class="sort">
</ul>
<div class="option">
<div class="steps">Moves:</div>
<div class="count">0</div>
<div class="act-img">
<img src="imgs/img-01.jpg" alt="" />
</div>
<div class="act-level">
<span>easy for test</span>
<button id="exit">exit img</button>
</div>
</div>
</div>
<div class="win" style="opacity: 1;">
<h2>congratulation you made it ^_^</h2>
<div class="steps">you win in:</div>
<div class="count">0</div>
<span>Play More</span>
</div>
</div>