移动端卡牌点击翻转功能失效问题求助
移动端卡牌翻转功能失效问题解决方案
问题描述
这是一款需集齐3张Ace卡牌即可获胜的9卡牌游戏,PC端通过click事件监听器实现卡牌翻转匹配功能正常,但移动端无法触发卡牌翻转。已尝试调整-webkit前缀的transform属性、添加touchstart事件监听器,均无效果。
核心问题分析
- 事件目标获取兼容性问题:代码中使用
e.path[1]获取点击的卡牌元素,但path属性并非所有移动端浏览器都支持,导致无法正确定位目标元素。 - 触摸事件默认行为干扰:移动端浏览器的默认触摸行为(如双击缩放、滚动)可能阻塞自定义触摸事件的触发。
- 响应式布局中层叠失效:移动端媒体查询中将
.card-back设置为position: static,破坏了卡牌正反两面的层叠关系,导致翻转效果无法正常显示。
解决方案
1. 替换兼容的元素获取方式
将e.path[1]替换为e.currentTarget(事件绑定的目标元素,即.card-toFlip),确保在所有浏览器中都能正确获取点击的卡牌:
function flipCard(e) { let clickedCard = e.currentTarget; // 替换原e.path[1] // 后续逻辑保持不变 }
2. 禁用浏览器默认触摸行为
在.card-toFlip的CSS中添加touch-action: manipulation,阻止浏览器默认触摸行为,提升触摸交互响应性:
.card-toFlip { touch-action: manipulation; transform-style: preserve-3d; transition: all 0.8s ease; text-align: center; height: 100%; width: 100%; }
3. 修复响应式布局层叠问题
修改移动端媒体查询中.card-back的定位属性,保持position: absolute以维持卡牌正反层叠关系,同时调整left值与.card-front一致:
/* 针对max-width:767px的媒体查询 */ .card-toFlip .card-back { position: absolute; left: 25%; width: 130px; height: 190px; margin-bottom: 5vw; backface-visibility: hidden; -webkit-backface-visibility: hidden; } /* 同理修改其他移动端媒体查询中的.card-back样式 */ @media (min-width:768px) and (max-width:991px) { .card-toFlip .card-back { position: absolute; left: 25%; width: 130px; height: 190px; margin-bottom: 11vw; backface-visibility: hidden; -webkit-backface-visibility: hidden; } } @media (min-width:992px) and (max-width:1199px) { .card-toFlip .card-back { position: absolute; left: 15%; width: 130px; height: 190px; margin-bottom: 11vw; } }
4. 简化事件绑定代码
合并click和touchstart事件的绑定,减少冗余代码:
cards.forEach(card => { card.addEventListener('click', flipCard); card.addEventListener('touchstart', flipCard); });
完整修改后代码示例
JavaScript
var cards = document.querySelectorAll(".card-toFlip"); let cardOne, cardTwo, cardThree; function flipCard(e) { let clickedCard = e.currentTarget; if (clickedCard != cardOne) { clickedCard.classList.add('is-flipped'); if (!cardOne) { cardOne = clickedCard; let cardOneImg = cardOne.querySelector('.card-front').getAttribute('alt'); if (cardOneImg != "ace") { setTimeout(() => { cardOne.classList.toggle('vibration'); }, 1000); setTimeout(() => { cardOne.classList.remove('is-flipped'); }, 3000); } return } if (!cardTwo) { cardTwo = clickedCard; let cardOneImg = cardOne.querySelector('.card-front').getAttribute('alt'); let cardTwoImg = cardTwo.querySelector('.card-front').getAttribute('alt'); if (cardOneImg === "ace" && cardTwoImg != "ace") { setTimeout(() => { cardOne.classList.add('vibration'); cardTwo.classList.add('vibration'); }, 1000); setTimeout(() => { cardOne.classList.remove('is-flipped'); cardTwo.classList.remove('is-flipped'); }, 3000); } return } cardThree = clickedCard; let cardOneImg = cardOne.querySelector('.card-front').getAttribute('alt'); let cardTwoImg = cardTwo.querySelector('.card-front').getAttribute('alt'); let cardThreeImg = cardThree.querySelector('.card-front').getAttribute('alt'); matchCards(cardOneImg, cardTwoImg, cardThreeImg); } }; cards.forEach(card => { card.addEventListener('click', flipCard); card.addEventListener('touchstart', flipCard); });
CSS
* { margin: 0; padding: 0; box-sizing: border-box; } body { background: radial-gradient(circle at 10% 20%, rgb(0, 0, 0) 0%, rgb(64, 64, 64) 90.2%); } header { color: #fff; text-align: center; } .headline { font-size: 5vw; margin-top: 5vw; } header p { padding-top: 1vw; } .sub-text { font-size: 1.5vw; } .cards-background { margin-top: 6vw; display: flex; flex-direction: row; justify-content: center; perspective: 1000px; -webkit-perspective: 1000px; position: relative; } .card-toFlip { touch-action: manipulation; transform-style: preserve-3d; transition: all 0.8s ease; text-align: center; height: 100%; width: 100%; } .card-toFlip .card-back { position: absolute; left: 3%; margin: 0vw 0.5vw; border-radius: 0.5vw; width: 130px; height: 190px; backface-visibility: hidden; -webkit-backface-visibility: hidden; } .card-toFlip.is-flipped { transform: rotateY(180deg); animation: normal 0.5s ease; } .card-toFlip .card-front { position: absolute; border-radius: 0.5vw; transform: rotateY(180deg); left: 3%; margin: 0vw 0.5vw; width: 130px; height: 190px; backface-visibility: hidden; -webkit-backface-visibility: hidden; } .cards-background img:hover { box-shadow: 3px 3px 3px grey; cursor: pointer; } .card-toFlip.is-flipped.vibration { animation: vibration 0.4s ease-in-out; transform: rotateY(0deg); } @keyframes vibration { 0%, 100% { transform: translateX(0); -webkit-transform: translate3d(0, 0, 0); } 20% { transform: translateX(-13px); -webkit-transform: translate3d(-13px, 0, 0); } 40% { transform: translateX(13px); -webkit-transform: translate3d(13px, 0, 0); } 60% { transform: translateX(-8px); -webkit-transform: translate3d(-8px, 0, 0); } 80% { transform: translateX(8px); -webkit-transform: translate3d(8px, 0, 0); } } @media (min-width:992px) and (max-width:1199px) { .headline { margin: 10vw 3vw 0vw; } .cards-background { justify-content: center; perspective: 1000px; display: flex; flex-wrap: wrap; margin: 13vw 2vw 2vw 2vw; } .card-toFlip { width: 19%; } .card-toFlip .card-front { width: 130px; height: 190px; left: 15%; } .card-toFlip .card-back { position: absolute; left: 15%; width: 130px; height: 190px; margin-bottom: 11vw; } } @media (min-width:768px) and (max-width:991px) { .headline { margin: 10vw 3vw 0vw; font-size: 7vw; } header p { margin: 0.5vw; } .sub-text { font-size: 3vw; } .cards-background { justify-content: center; perspective: 1000px; display: flex; flex-wrap: wrap; margin: 13vw 2vw 2vw 2vw; } .card-toFlip { width: 30%; transition: transform 0.5s; transform-style: preserve-3d; } .card-toFlip .card-front { width: 130px; height: 190px; left: 25%; transform: rotateY(180deg); -webkit-transform: rotateY(180deg); backface-visibility: hidden; -webkit-backface-visibility: hidden; } .card-toFlip .card-back { position: absolute; left: 25%; width: 130px; height: 190px; margin-bottom: 11vw; backface-visibility: hidden; -webkit-backface-visibility: hidden; } } @media (max-width:767px) { .headline { margin: 10vw 3vw 0vw; } .sub-text { font-size: 2vw; } .cards-background { justify-content: center; perspective: 1000px; display: flex; flex-wrap: wrap; margin: 8vw 2vw 2vw 2vw; } .card-toFlip { width: 30%; transition: transform 0.8s; transform-style: preserve-3d; } .card-toFlip .card-front { width: 130px; height: 190px; left: 25%; transform: rotateY(180deg); -webkit-transform: rotateY(180deg); backface-visibility: hidden; -webkit-backface-visibility: hidden; } .card-toFlip .card-back { position: absolute; left: 25%; width: 130px; height: 190px; margin-bottom: 5vw; backface-visibility: hidden; -webkit-backface-visibility: hidden; } }
HTML
<main style="height:100vh"> <div class="cards-background"> <div class="card1 card-toFlip"> <img src="images/back.png" class="card-back"> <img src="images/2_of_clubs.png" class="card-front" alt="2"> </div> <div class="card2 card-toFlip"> <img src="images/back.png" class="card-back"> <img src="images/ace_of_clubs.png" class="card-front" alt="ace"> </div> <div class="card3 card-toFlip"> <img src="images/back.png" class="card-back"> <img src="images/3_of_clubs.png" class="card-front" alt="3"> </div> <div class="card4 card-toFlip"> <img src="images/back.png" class="card-back"> <img src="images/4_of_clubs.png" class="card-front" alt="4"> </div> <div class="card5 card-toFlip"> <img src="images/back.png" class="card-back"> <img src="images/ace_of_clubs.png" class="card-front" alt="ace"> </div> <div class="card6 card-toFlip"> <img src="images/back.png" class="card-back"> <img src="images/5_of_clubs.png" class="card-front" alt="5"> </div> <div class="card7 card-toFlip"> <img src="images/back.png" class="card-back"> <img src="images/6_of_clubs.png" class="card-front" alt="6"> </div> <div class="card8 card-toFlip"> <img src="images/back.png" class="card-back"> <img src="images/7_of_clubs.png" class="card-front" alt="7"> </div> <div class="card9 card-toFlip"> <img src="images/back.png" class="card-back"> <img src="images/ace_of_clubs.png" class="card-front" alt="ace"> </div> </div> </main>
内容的提问来源于stack exchange,提问作者Ahmed Roushdy
相关产品推荐
相关产品推荐

