在记忆游戏中点击卡片不会翻转它

Posted

技术标签:

【中文标题】在记忆游戏中点击卡片不会翻转它【英文标题】:Clicking card in memory game doesn't flip it over 【发布时间】:2018-05-30 08:17:11 【问题描述】:

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

CodePen

for循环:

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;

【问题讨论】:

控制台中显示您的 Codepen 中有错误。当你摆脱这些 - 我看到一些翻转。 只要解决错误,代码就可以工作了:) 【参考方案1】:

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

startGame 函数中,deck.appendChild 不是函数。甲板用 document.getElementsByClassName('card-deck') 初始化。并且 document.getElementsByClassName 返回一个数组。您需要选择此数组的第一个索引。 在startGame 函数中,interval 未定义。在声明 interval 变量之前调用您的函数。使用 var 关键字声明它的 interval 变量声明向上移动以“保留”标识符。

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://***.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>

【讨论】:

以上是关于在记忆游戏中点击卡片不会翻转它的主要内容,如果未能解决你的问题,请参考以下文章

iOS - 仅针对特定视图翻转动画

JQuery 的容器结构问题 - 包含容器

记忆游戏卡旋转不正确

如何在两个视图不正确时自动翻转它们

Codeforces 892E Envy

React Native Flip Card 不支持翻转