首页 > 解决方案 > 如何让事件监听器只触发一次?

问题描述

我正在用 6 张卡片构建一个非常简单的记忆匹配游戏。每张卡片都在一个包含另外两个元素div的类中- 卡片的正面(只是一个简单的绿色背景 img)和卡片的背面(我选择的随机图像)。.carddiv

背面 在此处输入图像描述

正面 在此处输入图像描述

每张卡片都有一个点击事件监听器。单击卡片后,卡片会从背面旋转到正面并显示图像。如果您选择的两张图片匹配,您将获得 +1分数。如果您选择的图像不匹配,则所有卡片都会旋转到它们的背面,并且您会收到 +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>

我还是新手,所以任何提示都会受到欢迎,谢谢。

标签: javascripthtmlcss

解决方案


如果你委托你可以测试比关闭事件处理程序更好

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
  }
})

推荐阅读