简体   繁体   中英

attaching event & function to dynamic element with Vanilla JS

I created Memory Card Game that has 12 card on Easy difficulty , I wanted to add more card by creating new Dynamic Element and append it to the game container whenever I change difficulty.

with this code i want the new created element to have the flipCard() function which will flip the card when i click it. however this isn't working, whenever i clicked the card its gave me an error

'TypeError: this.classlist is undefined' (An error Inside flipCard function)

game.addEventListener('click', function (e) {
     if (e.target) {
         flipCard();
    }
});

This code below will work, but not for dynamic element.

 cards.forEach(card => {
     cardCount.push(card);
     card.addEventListener('click', flipCard);
 });

 window.onload = function() { const game = document.querySelector('.game'); const cards = document.querySelectorAll('.card'); const scoreboard = document.querySelector('.score'); const move = document.querySelector('.move'); const difficulties = document.getElementById("difficulties"); let isCardFlipped = false, lockBoard = false, firstCard, secondCard, score = 0, moves = 0, unflipTimeout = 1500, cardCount = []; difficulties.addEventListener("change", function() { resetGame(); }); function addCard() { for (i = 0; i < 4; i++) { game.innerHTML += "<div class='card'>" + "<img src='assets/image/default/bellsprout.svg' class='front-face'>" + "<img src='assets/image/default/pokeball.svg' class='back-face'>" + "</div>"; } }; // ATTACH CLICK EVENT AND flipCard() FUNCTION FOR EVERY CARD. // THIS DOESN'T WORK FOR DYNAMICALLY CREATED ELEMENT // cards.forEach(card => { // cardCount.push(card); // card.addEventListener('click', flipCard); // }); // ATTACH CLICK EVENT AND flipCard() FUNCTION FOR EVERY CARD. // THIS WILL WORK FOR DYNAMICALLY CREATED ELEMENT, // BUT "this." INSIDE flipCard() function is not defined/initialize game.addEventListener('click', function(e) { if (e.target) { flipCard(); } }); // Difficulty Option (difficulty = () => { let selected = difficulties.options[difficulties.selectedIndex].value; if (selected === 'easy') { unflipTimeout = 1500; } else if (selected === 'hard') { unflipTimeout = 500; // ADD MORE CARD ONLY IF HARD DIFFICULTY IS SELECTED addCard(); } })(); // flip card when card is clicked function flipCard() { if (lockBoard || this === firstCard) return; this.classList.add('flip'); if (!isCardFlipped) { isCardFlipped = true; firstCard = this; return; } isCardFlipped = false; secondCard = this; checkForMatch(); } // check if 2 selected card are match. checkForMatch = () => { // if matched disabled card function, unflip card if not matched. let isMatch = firstCard.dataset.pokemon === secondCard.dataset.pokemon; isMatch ? disableCard() : unflipCard(unflipTimeout); } // disable flip card function disableCard = () => { moves++; score++; updateScore(); firstCard.removeEventListener('click', flipCard); secondCard.removeEventListener('click', flipCard); } unflipCard = (timeout) => { lockBoard = true; moves++; updateScore(); setTimeout(() => { firstCard.classList.remove('flip'); secondCard.classList.remove('flip'); resetBoard(); }, timeout); } resetBoard = () => { [isCardFlipped, lockBoard] = [false, false]; [firstCard, secondCard] = [null, null]; } resetGame = () => { if (moves > 0) { var confirm = window.confirm("Changes will be applied after reset \\n \\n \\t \\t Reset The Game?"); if (confirm === true) { score = 0; moves = 0; updateScore(); for (var i = 0; i < cardCount.length; i++) { cardCount[i].classList.remove('flip'); } alert('Game Restarted! \\n \\n \\t Card Reshuffle.'); shuffle(); } else return; } } var shuffle; (shuffle = () => { cards.forEach(card => { let randomPos = Math.round(Math.random() * cardCount.length); card.style.order = randomPos; }); })(); updateScore = () => { scoreboard.innerText = score; move.innerText = moves; if (score === cardCount.length / 2) { alert("You Win!"); } } }; 
 .scoreboard { display: flex; flex-flow: row nowrap; justify-content: space-around; align-items: center; padding: 2px; border-radius: 5px; background: #363636; color: #0a8ec2; } .scoreboard h1 { font-size: 1.5rem; } .game { width: 580px; height: 580px; margin: auto; display: flex; flex-wrap: wrap; perspective: 1000px; position: relative; } .game .card { position: relative; width: calc(25% - 10px); height: calc(33.333% - 10px); margin: 5px; transform-style: preserve-3d; transition: transform 500ms linear; } .game .card.active { transform: scale(0.97); } .game .card.flip { transform: rotateY(180deg); } .game .card .front-face, .game .card .back-face { width: 100%; height: 100%; position: absolute; border-radius: 5px; padding: 20px; background: #363636; backface-visibility: hidden; } .game .card .front-face { transform: rotateY(180deg); backface-visibility: visible; } 
 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <link rel="stylesheet" href="assets/css/styles.css"> <script src="assets/js/jquery.min.js"></script> <script src="assets/js/main.js"></script> <script src="assets/js/app.js"></script> <title>Memory Card Game</title> </head> <body> <section class="scoreboard"> <h1>Score: <span class="score">0</span> <br> Moves: <span class="move">0</span></h1> <select id="difficulties" name="difficulties"> <option value="default" disabled>Select Difficulty</option> <option value="easy" selected>Easy</option> <option value="hard">Hard</option> </select> </section> <main class="game"> <div class="card" data-pokemon="rattata"> <img src="assets/image/default/rattata.svg" alt="Rattata" class="front-face"> <img src="assets/image/default/pokeball.svg" alt="Pokemon" class="back-face"> </div> <div class="card" data-pokemon="rattata"> <img src="assets/image/default/rattata.svg" alt="Rattata" class="front-face"> <img src="assets/image/default/pokeball.svg" alt="Pokemon" class="back-face"> </div> <div class="card" data-pokemon="meowth"> <img src="assets/image/default/meowth.svg" alt="Meowth" class="front-face"> <img src="assets/image/default/pokeball.svg" alt="Pokemon" class="back-face"> </div> <div class="card" data-pokemon="meowth"> <img src="assets/image/default/meowth.svg" alt="Meowth" class="front-face"> <img src="assets/image/default/pokeball.svg" alt="Pokemon" class="back-face"> </div> <div class="card" data-pokemon="mew"> <img src="assets/image/default/mew.svg" alt="Mew" class="front-face"> <img src="assets/image/default/pokeball.svg" alt="Pokemon" class="back-face"> </div> <div class="card" data-pokemon="mew"> <img src="assets/image/default/mew.svg" alt="Mew" class="front-face"> <img src="assets/image/default/pokeball.svg" alt="Pokemon" class="back-face"> </div> <div class="card" data-pokemon="mankey"> <img src="assets/image/default/mankey.svg" alt="Mankey" class="front-face"> <img src="assets/image/default/pokeball.svg" alt="Pokemon" class="back-face"> </div> <div class="card" data-pokemon="mankey"> <img src="assets/image/default/mankey.svg" alt="Mankey" class="front-face"> <img src="assets/image/default/pokeball.svg" alt="Pokemon" class="back-face"> </div> <div class="card" data-pokemon="venonat"> <img src="assets/image/default/venonat.svg" alt="Venonat" class="front-face"> <img src="assets/image/default/pokeball.svg" alt="Pokemon" class="back-face"> </div> <div class="card" data-pokemon="venonat"> <img src="assets/image/default/venonat.svg" alt="Venonat" class="front-face"> <img src="assets/image/default/pokeball.svg" alt="Pokemon" class="back-face"> </div> <div class="card" data-pokemon="psyduck"> <img src="assets/image/default/psyduck.svg" alt="Psyduck" class="front-face"> <img src="assets/image/default/pokeball.svg" alt="Pokemon" class="back-face"> </div> <div class="card" data-pokemon="psyduck"> <img src="assets/image/default/psyduck.svg" alt="Psyduck" class="front-face"> <img src="assets/image/default/pokeball.svg" alt="Pokemon" class="back-face"> </div> </main> </body> </html> 

Instead of this:

if (e.target) {
   flipCard();
 }

Do this:

if (e.target) {
   flipCard.bind(this)();
 }

Add this into the click listener. Your this from the flipCard function points to window .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM