简体   繁体   中英

Clicking card in memory game doesn't flip it over

I'm trying to make a memory game and am struggling to get the cards to flip over when they're clicked. I expected the following for loop to call the function displayCard when a card (corresponding to each li item with class card ) is clicked, which function toggles the classes show and open (sets the card to visible [displays icon] and changes the background color). Any suggestions?

CodePen

For loop:

for (let i = 0; i < cards.length; i++) {
  card = cards[i];
  card.addEventListener('click', displayCard);
  card.addEventListener('click', cardOpen);
  card.addEventListener('click', congratulations);
}

displayCard function:

let displayCard = function() {
  this.classList.toggle('open');
  this.classList.toggle('show');
  this.classList.toggle('disabled');
};

CSS for classes show and open :

.card-deck .card.open {
    /* transform: rotateY(0); */
    background: #02b3e4;
    cursor: default;
    animation-name: flipInY;
    -webkit-backface-visibility: visible !important;
    backface-visibility: visible !important;
    animation-duration: .75s;
}

.card-deck .card.show {
    font-size: 33px;
}

.show {
    visibility: visible !important;
    opacity: 100 !important;
}

There are two errors in your code that need to be fixed and then the flipping occurs :

  • in the startGame function, deck.appendChild is not a function. deck was initialized with document.getElementsByClassName('card-deck'). And document.getElementsByClassName returns an array. You need to select the first index of this array.
  • in the startGame function, interval is not defined. Your function is called before the interval variable is declared. Either move up the interval variable declaration of declare it with the var keyword to "reserve" the identifier.

 let card = document.getElementsByClassName('card'); // Spread operator (new in ES6) allows iterable to expand where 0+ arguments are expected let cards = [...card]; let deck = document.getElementsByClassName('card-deck')[0]; let moves = 0; let counter = document.querySelector('.moves'); let stars = document.querySelectorAll('.fa-star'); let matchingCard = document.getElementsByClassName('matching'); let starsList = document.querySelectorAll('.stars li'); let closeIcon = document.querySelector('.close'); let modal = document.getElementsByClassName('main-modal'); let openedCards = []; // Game timer let second = 0, minute = 0, hour = 0; let timer = document.querySelector('.timer'); let interval; // Shuffle function from http://stackoverflow.com/a/2450976 function shuffle(array) { let currentIndex = array.length, temporaryValue, randomIndex; while (currentIndex !== 0) { randomIndex = Math.floor(Math.random() * currentIndex); currentIndex -= 1; temporaryValue = array[currentIndex]; array[currentIndex] = array[randomIndex]; array[randomIndex] = temporaryValue; } return array; } // Shuffles cards upon page load document.body.onload = startGame(); function startGame() { // Shuffles deck cards = shuffle(cards); // Removes any existing classes from each card for (let i = 0; i < cards.length; i++) { deck.innerHTML = ''; [].forEach.call(cards, function(item) { deck.appendChild(item); }); cards[i].classList.remove('show', 'open', 'matching', 'disabled'); } // Resets number of moves moves = 0; counter.innerHTML = moves; // Resets star rating for (let i = 0; i < stars.length; i++) { stars[i].style.color = '#ffd700'; stars[i].style.visibility = 'visible'; } // Resets timer let second = 0; let minute = 0; let hour = 0; let timer = document.querySelector('.timer'); timer.innerHTML = '0 mins 0 secs'; if (typeof interval != "undefined") { sclearInterval(interval); } } // Toggles open and show classes to display cards let displayCard = function() { this.classList.toggle('open'); this.classList.toggle('show'); this.classList.toggle('disabled'); }; // Adds opened cards to openedCards list and checks if cards are a match or not function cardOpen() { openedCards.push(this); let len = openedCards.length; if (len === 2) { moveCounter(); if (openedCards[0].type === openedCards[1].type) { matching(); } else { notMatching(); } } } // When cards match function matching() { openedCards[0].classList.add('matching', 'disabled'); openedCards[1].classList.add('matching', 'disabled'); openedCards[0].classList.remove('show', 'open'); openedCards[1].classList.remove('show', 'open'); openedCards = []; } // When cards don't match function notMatching() { openedCards[0].classList.add('not-matching'); openedCards[1].classList.add('not-matching'); disable(); setTimeout(function() { openedCards[0].classList.remove('show', 'open', 'not-matching'); openedCards[1].classList.remove('show', 'open', 'not-matching'); enable(); openedCards = []; }, 1100); } // Disables cards temporarily function disable() { Array.prototype.filter.call(cards, function(card) { card.classList.add('disabled'); }); } // Enables cards, disables matching cards function enable() { Array.prototype.filter.call(cards, function(card) { card.classList.remove('disabled'); for (let i = 0; i < matchingCard.length; i++) { matchingCard[i].classList.add('disabled'); } }); } // Counts player's moves function moveCounter() { moves++; counter.innerHTML = moves; // Starts timer on first click if (moves == 1) { second = 0; minute = 0; hour = 0; startTimer(); } // Sets star rating based on number of moves if (moves > 8 && moves < 12) { for (i = 0; i < 3; i++) { if (i > 1) { stars[i].style.visibility = 'collapse'; } } } else if (moves > 13) { for (i = 0; i < 3; i++) { if (i > 0) { stars[i].style.visibility = 'collapse'; } } } } function startTimer() { interval = setInterval(function() { timer.innerHTML = minute + 'mins ' + second + 'secs'; second++; if (second == 60) { minute++; second = 0; } if (minute == 60) { hour++; minute = 0; } }, 1000); } // Congratulates player when all cards match and shows modal, moves, time and rating function congratulations() { if (matchingCard.length == 16) { clearInterval(interval); let finalTime = timer.innerHTML; // Shows congratulations modal modal.classList.add('show'); let starRating = document.querySelector('.stars').innerHTML; // Shows move, time, and rating on modal document.getElementsByClassName('final-move').innerHTML = moves; document.getElementsByClassName('star-rating').innerHTML = starRating; document.getElementsByClassName('total-time').innerHTML = finalTime; closeModal(); } } // Closes modal upon clicking its close icon function closeModal() { closeIcon.addEventListener('click', function(e) { modal.classList.remove('show'); startGame(); }); } function reset() { modal.classList.remove('show'); startGame(); } // Adds event listeners to each card for (let i = 0; i < cards.length; i++) { card = cards[i]; card.addEventListener('click', displayCard); card.addEventListener('click', cardOpen); card.addEventListener('click', congratulations); } 
 html { box-sizing: border-box; } *, *::before, *::after { box-sizing: inherit; } html, body { width: 100%; height: 100%; margin: 0; padding: 0; } body { background: #ffffff; font-family: 'Permanent Marker', cursive; font-size: 16px; } .container { display: flex; justify-content: center; align-items: center; flex-direction: column; } h1 { font-family: 'Gloria Hallelujah', cursive; } /* DECK OF CARDS */ .card-deck { width: 85%; background: #716F71; padding: 1rem; border-radius: 4px; box-shadow: 8px 9px 26px 0 rgba(46, 61, 73, 0.5); display: flex; flex-wrap: wrap; justify-content: space-around; align-items: center; margin: 0 0 3em; } .card-deck .card { height: 3.7rem; width: 3.7rem; margin: 0.2rem 0.2rem; background: #141214;; font-size: 0; color: #ffffff; border-radius: 5px; cursor: pointer; display: flex; justify-content: center; align-items: center; box-shadow: 5px 2px 20px 0 rgba(46, 61, 73, 0.5); } .card-deck .card.open { /* transform: rotateY(0); */ background: #02b3e4; cursor: default; animation-name: flipInY; -webkit-backface-visibility: visible !important; backface-visibility: visible !important; animation-duration: .75s; } .card-deck .card.show { font-size: 33px; } .show { visibility: visible !important; opacity: 100 !important; } .card-deck .card.matching { cursor: default; background: #E5F720; font-size: 33px; animation-name: rubberBand; -webkit-backface-visibility: visible !important; backface-visibility: visible !important; animation-duration: .75s; } .card-deck .card.not-matching { animation-name: pulse; -webkit-backface-visibility: visible !important; backface-visibility: visible !important; animation-duration: .75s; background: #e2043b; } .card-deck .card.disabled { pointer-events: none; opacity: 0.9; } /* SCORE PANEL */ .score-panel { text-align: left; margin-bottom: 10px; } .score-panel .stars { margin: 0; padding: 0; display: inline-block; margin: 0 5px 0 0; } .score-panel .stars li { list-style: none; display: inline-block; } .score-panel .restart { float: right; cursor: pointer; } .fa-star { color: #FFD700; } .timer { display: inline-block; margin: 0 1rem; } /* CONGRATULATIONS MODAL */ .overlay { position: fixed; top: 0; bottom: 0; left: 0; right: 0; background: rgba(0, 0, 0, 0.7); transition: opacity 500ms; visibility: hidden; opacity: 0; } .overlay:target { visibility: visible; opacity: 1; } .popup { margin: 70px auto; padding: 20px; background: #ffffff; border-radius: 5px; width: 85%; position: relative; transition: all 5s ease-in-out; font-family: 'Gloria Hallelujah', cursive; } .popup h2 { margin-top: 0; color: #333; font-family: Tahoma, Arial, sans-serif; } .popup .close { position: absolute; top: 20px; right: 30px; transition: all 200ms; font-size: 30px; font-weight: bold; text-decoration: none; color: #333; } .popup .close:hover { color: #e5f720; } .popup .congrats-message, .info-message { max-height: 30%; overflow: auto; text-align: center; } .star-rating li { display: inline-block; } .play-again { background-color: #141214; padding: 0.7rem 1rem; font-size: 1.1rem; display: block; margin: 0 auto; width: 50%; font-family: 'Gloria Hallelujah', cursive; color: #ffffff; border-radius: 5px; } /* Animations */ @keyframes flipInY { from { transform: perspective(400px) rotate3d(0, 1, 0, 90deg); animation-timing-function: ease-in; opacity: 0; } 40% { transform: perspective(400px) rotate3d(0, 1, 0, -20deg); animation-timing-function: ease-in; } 60% { transform: perspective(400px) rotate3d(0, 1, 0, 10deg); opacity: 1; } 80% { transform: perspective(400px) rotate3d(0, 1, 0, -5deg); } to { transform: perspective(400px); } } @keyframes rubberBand { from { transform: scale3d(1, 1, 1); } 30% { transform: scale3d(1.25, 0.75, 1); } 40% { transform: scale3d(0.75, 1.25, 1); } 50% { transform: scale3d(1.15, 0.85, 1); } 65% { transform: scale3d(.95, 1.05, 1); } 75% { transform: scale3d(1.05, .95, 1); } to { transform: scale3d(1, 1, 1); } } @keyframes pulse { from { transform: scale3d(1, 1, 1); } 50% { transform: scale3d(1.2, 1.2, 1.2); } to { transform: scale3d(1, 1, 1); } } /* MEDIA QUERIES */ @media (max-width: 320px) { .card-deck { width: 85%; } .card-deck .card { height: 4.7rem; width: 4.7rem; } } /* For tablets and larger screens */ @media (min-width: 768px) { .container { font-size: 22px; } .card-deck { width: 660px; height: 680px; } .card-deck .card { height: 125px; width: 125px; } .popup { width: 60%; } } 
 <!-- <!doctype html> --> <html lang="en"> <head> <meta charset="utf-8"> <title>Matching Game</title> <meta name="description" content=""> <link rel="stylesheet prefetch" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.6.1/css/font-awesome.min.css"> <link rel="stylesheet prefetch" href="https://fonts.googleapis.com/css?family=Coda"> <link rel="stylesheet" href="index.css"> </head> <body> <div class="container"> <header> <h1>Matching Game</h1> </header> <section class="score-panel"> <ul class="stars"> <li><i class="fa fa-star"></i></li> <li><i class="fa fa-star"></i></li> <li><i class="fa fa-star"></i></li> </ul> <span class="moves">0</span> moves <div class="timer"></div> <div class="restart" onclick=startGame()> <i class="fa fa-repeat"></i> </div> </section> <ul class="card-deck"> <li class="card" type="diamond"> <i class="fa fa-diamond"></i> </li> <li class="card" type="plane"> <i class="fa fa-paper-plane-o"></i> </li> <li class="card matching" type="anchor"> <i class="fa fa-anchor"></i> </li> <li class="card" type="bolt" > <i class="fa fa-bolt"></i> </li> <li class="card" type="cube"> <i class="fa fa-cube"></i> </li> <li class="card matching" type="anchor"> <i class="fa fa-anchor"></i> </li> <li class="card" type="leaf"> <i class="fa fa-leaf"></i> </li> <li class="card" type="bicycle"> <i class="fa fa-bicycle"></i> </li> <li class="card" type="diamond"> <i class="fa fa-diamond"></i> </li> <li class="card" type="bomb"> <i class="fa fa-bomb"></i> </li> <li class="card" type="leaf"> <i class="fa fa-leaf"></i> </li> <li class="card" type="bomb"> <i class="fa fa-bomb"></i> </li> <li class="card open show" type="bolt"> <i class="fa fa-bolt"></i> </li> <li class="card" type="bicycle"> <i class="fa fa-bicycle"></i> </li> <li class="card" type="plane"> <i class="fa fa-paper-plane-o"></i> </li> <li class="card" type="cube"> <i class="fa fa-cube"></i> </li> </ul> <div class="main-modal overlay"> <div class="popup"> <h2>Congratulations!</h2> <a class="close" href=# >×</a> <div class="congrats-message"> Congratulations, you're a winner! </div> <div class="info-message"> <p>You made <span class=final-move></span> moves </p> <p>In <span class=total-time></span></p> <p>Rating: <span class=star-rating></span></p> </div> <button class="play-again" onclick="reset()"> Play again </button> </div> </div> </div> <script src="index.js"></script> </body> </html> 

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