You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

塔罗牌游戏开发:如何正确输出数组中存储的选中DIV元素

解决塔罗牌游戏中卡牌显示异常与重复输出问题

我帮你分析下遇到的两个核心问题,再给出针对性的修复方案:

问题1:显示[object HTMLDivElement]

你把整个card DOM元素直接存入了chosenCards数组,当你把DOM元素和字符串拼接时,JavaScript会默认调用它的toString()方法,结果就会变成[object HTMLDivElement]。你真正需要的是卡牌正面的文本内容,而非DOM元素本身。

问题2:重复输出3次

每次点击卡牌时,你都会循环整个chosenCards数组并把内容追加到结果容器里。比如:

  • 选第一张卡牌时,数组长度为1,输出1次;
  • 选第二张卡牌时,数组长度变为2,又循环2次追加内容,最终总共输出1+2=3次,这就是重复的原因。

修改后的完整代码(关键改动已标注)

let chosenCards = new Array(); // 提前声明数组,避免变量提升问题
const holder = document.getElementById("cardResults"); // 提前获取结果容器,避免重复查找DOM

class tarot {
  constructor(cards) {
    this.cardsArray = cards;
  }
  startReading() {
    this.shuffleCards(this.cardsArray);
  }
  flipCard(card, cards) {
    if (this.canFlipCard(card)) {
      if (chosenCards.length >= 2) {
        console.log("已选满2张卡牌,停止选择");
        // 修正遍历DOM数组的方式:用for-of替代for-in
        for (let cardItem of cards) {
          const list = cardItem.classList;
          if (list && !list.contains('visible')) {
            cardItem.removeEventListener('click', cardItem.fn);
          }
        }
      } else if (!card.classList.contains('visible')) {
        card.classList.add('visible');
        // 关键改动1:提取卡牌正面的文本内容存入数组
        const cardFrontText = card.querySelector('.card-front').textContent.trim();
        chosenCards.push(cardFrontText);
        
        // 关键改动2:只追加当前选中的卡牌内容,而非循环整个数组
        holder.innerHTML += `<p>${cardFrontText}</p><br>`;
        
        card.removeEventListener('click', card.fn);
      }
    }
  }
  shuffleCards(cardsArray) {
    for (let i = cardsArray.length - 1; i > 0; i--) {
      const randIndex = Math.floor(Math.random() * (i + 1));
      [cardsArray[i], cardsArray[randIndex]] = [cardsArray[randIndex], cardsArray[i]];
    }
    // 用forEach替代map:map需要返回值,这里仅需修改样式,forEach更合适
    cardsArray.forEach((card, index) => {
      card.style.order = index;
    });
  }
  getCardType(card) {
    // 增加可选链,避免找不到元素时报错
    return card.querySelector('.card-value')?.src;
  }
  canFlipCard(card) {
    return card;
  }
}

// 页面初始化逻辑
if (document.readyState === 'loading') {
  document.addEventListener('DOMContentLoaded', ready);
} else {
  ready();
}

function ready() {
  const cards = Array.from(document.getElementsByClassName('card'));
  const tarotReading = new tarot(cards);
  const overButtons = Array.from(document.getElementsByClassName('over'));
  
  overButtons.forEach(button => {
    button.addEventListener('click', () => {
      button.classList.remove('visible');
      // 洗牌时重置状态:清空选中数组、结果显示、恢复卡牌可点击状态
      chosenCards = [];
      holder.innerHTML = '';
      cards.forEach(card => {
        card.classList.remove('visible');
        // 重新绑定点击事件
        card.addEventListener('click', card.fn = function clicked() {
          tarotReading.flipCard(card, cards);
        });
      });
      tarotReading.startReading();
    });
  });
  
  // 初始化卡牌点击事件
  cards.forEach(card => {
    card.addEventListener('click', card.fn = function clicked() {
      tarotReading.flipCard(card, cards);
    });
  });
}
h1 {
  color: #7B68EE;
  padding: 5px 50px;
  text-align: center;
}
.container {
  display: grid;
  grid-template-columns: repeat(6, auto);
  grid-gap: 10px;
  margin: 50px;
  justify-content: center;
  perspective: 500px;
}
.card {
  position: relative;
  height: 175px;
  width: 125px;
}
.card-face {
  position: absolute;
  width: 100%;
  height: 100%;
  display: flex;
  justify-content: center;
  align-items: center;
  overflow: hidden;
  backface-visibility: hidden;
  border-radius: 12px;
  border: 1px solid white;
  transition: transform 500ms ease-in-out;
}
.card.visible .card-back {
  transform: rotateY(-180deg);
}
.card.visible .card-front {
  transform: rotateY(0);
}
.card-back {
  background-color: black;
  color: white;
}
.card-front {
  background-color: black;
  color: white;
  transform: rotateY(180deg);
}
<body>
  <h1>Tarot</h1>
  <div class="container">
    <div class="card">
      <div class="card-back card-face card1" id="card1">
        <p>1</p>
      </div>
      <div class="card-front card-face">
        <p>The Hermit</p>
      </div>
    </div>
    <div class="card">
      <div class="card-back card-face card2">
        <p>2</p>
      </div>
      <div class="card-front card-face">
        <p>The Fool</p>
      </div>
    </div>
    <div class="card">
      <div class="card-back card-face card3">
        <p>3</p>
      </div>
      <div class="card-front card-face">
        <p>The Empress</p>
      </div>
    </div>
  </div>
  <button type="button" class="over container">Shuffle</button>
  <hr>
  <div id="cardResults"></div>
</body>

核心改动说明

  1. 修复显示异常:通过card.querySelector('.card-front').textContent.trim()提取卡牌正面的文本,存入数组的是文本而非DOM元素,解决[object HTMLDivElement]问题。
  2. 解决重复输出:每次选中卡牌后,直接追加当前卡牌的文本内容到结果容器,不再循环整个数组,避免重复输出。
  3. 体验优化:洗牌时重置选中状态、清空结果显示,并重新绑定卡牌点击事件,保证每次洗牌后可以重新选择。

内容的提问来源于stack exchange,提问作者Chris

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 07:04:19