[英]How can I make an event listener fire only once?
我正在用 6 张卡片构建一个非常简单的记忆匹配游戏。 每张卡片都在一个.card
类的div
,该div
包含另外两个div
元素 - 卡片的正面(只是一个简单的绿色背景 img)和卡片的背面(我选择的随机图像)。
每张卡片都有一个点击事件监听器。 单击卡片后,卡片将从背面旋转到正面并显示图像。 如果您选择的两张图片匹配,您会收到 +1 Score 。 如果您选择的图像碰巧不匹配,则所有卡片都会旋转到其背面,您会收到“失败”+1,并且您输掉了游戏。
主要问题是由于事件侦听器,我可以一遍又一遍地单击和旋转同一张卡片。 有没有办法让它只火一次? 我曾尝试在事件侦听器上使用once: true
但这导致即使在输掉游戏后卡片也无法点击,因此我已将其删除。
const cards = document.querySelectorAll(".card"); const images = document.querySelectorAll("img"); let scoreElement = document.getElementById("score"); let failsElement = document.getElementById("fails"); let failsAmount = 0; let scoreAmount = 0; let pickedCards = []; function pickCards() { // Iterate through every div with the class of ".card" for (let i = 0; i < cards.length; i++) { // Add an event listener to them cards[i].addEventListener("click", function() { // Rotate the card cards[i].classList.toggle("flipcard"); // After clicking on the card that contains the img, push the img into the pickedCards array. pickedCards.push(images[i]); checkForMatch(); }); } } function checkForMatch() { // Check the source of the images from the array if (pickedCards[0].src == pickedCards[1].src) { alert("Match! +1 score"); scoreAmount++; scoreElement.textContent = "Score: " + scoreAmount; // Empty the array so the player can pick another 2 cards pickedCards = []; } else { hideCards(); alert("Not a match! Sorry!"); failsAmount++; failsElement.textContent = "Fails: " + failsAmount; pickedCards = []; } } function hideCards() { for (let i = 0; i < cards.length; i++) { setTimeout(function() { // Remove the flipcard class from the cards and show the front face again. cards[i].classList.remove("flipcard"); }, 1000); } } pickCards();
* { padding: 0; margin: 0; } *, *:before, *:after { box-sizing: inherit; } html { box-sizing: border-box; } html,body { height: 100%; } .card-container { display: flex; position: absolute; left: 50%; top: 50%; transform: translate(-50%,-50%); perspective: 1200; } .flipcard { transform: rotateY(-180deg); } .card { width: 200px; height: 200px; transition: all 0.7s; transform-style: preserve-3d; margin: 0em 1em; } .front-card, .back-card { width: 200px; height: 200px; position: absolute; top: 0; left: 0; backface-visibility: hidden; } .front-card { background: url("./IMGs/block.jpg") no-repeat center/cover; } .back-card { transform: rotateY(-180deg); } .back-card img { width: 200px; height: 200px; } #score, #fails { font-size: 2em; }
<div class="card-container"> <div class="card"> <div class="front-card"></div> <div id="card1" class="back-card"><img src="IMGs/eric.jpg" alt=""></div> </div> <div class="card"> <div class="front-card"></div> <div id="card2" class="back-card"><img src="IMGs/john.webp" alt=""></div> </div> <div class="card"> <div class="front-card"></div> <div id="card3" class="back-card"><img src="IMGs/salim.png" alt=""></div> </div> <div class="card"> <div class="front-card"></div> <div id="card4" class="back-card"><img src="IMGs/salim.png" alt=""></div> </div> <div class="card"> <div class="front-card"></div> <div id="card5" class="back-card"><img src="IMGs/eric.jpg" alt=""></div> </div> <div class="card"> <div class="front-card"></div> <div id="card6" class="back-card"><img src="IMGs/john.webp" alt=""></div> </div> </div> <p id="score">Score: 0</p> <p id="fails">Fails: 0</p>
我还是新手,所以任何提示都将得到认可,谢谢。
对于您的情况,只需在翻转和检查匹配之前添加一个 if 语句:
cards[i].addEventListener('click', function () {
if (!cards[i].classList.contains('flipcard')) {
cards[i].classList.toggle('flipcard')
pickedCards.push(images[i])
checkForMatch()
}
})
如果您委托,您可以进行比关闭事件处理程序更好的测试
document.querySelector(".card-container").addEventListener("click", function(e) {
const tgt = e.target.closest("div");
if (tgt && tgt.classList.contains("card")) {
if (tgt.classList.contains("clicked")) return;
tgt.classList.add("clicked");
.... // rest of handling here
}
})
这很容易解决。
创建一个数组或变量以检查是否单击了相应的卡片。 例子:
cardClicked = [假,假,假,假,假,假];
在点击事件上,将选中的cardsClicked[n] 修改为true。 并且,检查(如果)所选卡已被选中。
就是这样。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.