塔罗牌游戏开发:如何正确输出数组中存储的选中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>
核心改动说明
- 修复显示异常:通过
card.querySelector('.card-front').textContent.trim()提取卡牌正面的文本,存入数组的是文本而非DOM元素,解决[object HTMLDivElement]问题。 - 解决重复输出:每次选中卡牌后,直接追加当前卡牌的文本内容到结果容器,不再循环整个数组,避免重复输出。
- 体验优化:洗牌时重置选中状态、清空结果显示,并重新绑定卡牌点击事件,保证每次洗牌后可以重新选择。
内容的提问来源于stack exchange,提问作者Chris
相关产品推荐
相关产品推荐

