在记忆游戏中点击卡片不会将其翻转过来

时间:2018-05-30 08:17:11

标签: javascript

我正在尝试制作记忆游戏,并且在点击它们时我很难让卡片翻转。我期望以下for循环在单击一个卡(对应于具有类displayCard的每个li项)时调用函数card,该函数切换类showopen(将卡片设置为可见[显示图标]并更改背景颜色)。有什么建议?

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功能:

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

课程showopen的CSS:

.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;
}

1 个答案:

答案 0 :(得分:2)

您的代码中有两个错误需要修复,然后发生翻转:

    {li}在startGame函数中,deck.appendChild不是函数。 deck使用document.getElementsByClassName(&#39; card-deck&#39;)初始化。 document.getElementsByClassName返回一个数组。您需要选择此数组的第一个索引。 {li>在startGame函数中,interval未定义。在声明interval变量之前调用您的函数。向上移动interval变量声明,使用var关键字将其声明为&#34;保留&#34;标识符。

&#13;
&#13;
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);
}
&#13;
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%;
	}
}
&#13;
<!-- <!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>
&#13;
&#13;
&#13;