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

移动端卡牌点击翻转功能失效问题求助

移动端卡牌翻转功能失效问题解决方案

问题描述

这是一款需集齐3张Ace卡牌即可获胜的9卡牌游戏,PC端通过click事件监听器实现卡牌翻转匹配功能正常,但移动端无法触发卡牌翻转。已尝试调整-webkit前缀的transform属性、添加touchstart事件监听器,均无效果。

核心问题分析

  1. 事件目标获取兼容性问题:代码中使用e.path[1]获取点击的卡牌元素,但path属性并非所有移动端浏览器都支持,导致无法正确定位目标元素。
  2. 触摸事件默认行为干扰:移动端浏览器的默认触摸行为(如双击缩放、滚动)可能阻塞自定义触摸事件的触发。
  3. 响应式布局中层叠失效:移动端媒体查询中将.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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.08 22:45:38