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

Angular闪卡滑动切换问题:实现双向滑入滑出效果

实现Angular闪卡双向滑入滑出切换效果

你的核心问题在于只用单个卡片容器,无法同时展示当前卡片滑出和新卡片从另一侧滑入的双向动画。下面是具体的修改方案,通过双卡片容器叠加的方式实现流畅的双向切换效果:

1. HTML结构修改

添加两个卡片容器,分别对应当前显示的卡片和即将进入的卡片,通过Angular条件渲染控制它们的显示与动画状态:

<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.8.2/angular.min.js"></script>
<div class="flashcard-container" ng-app="flashcardApp" ng-controller="FlashcardController as flashCtrl">
  <button class="navigation-btn previous" ng-disabled="flashCtrl.currentCardIndex === 0" ng-click="flashCtrl.previousCard()">Previous</button>
  <!-- 双卡片视口容器,用于重叠放置两张卡片 -->
  <div class="flashcard-viewport">
    <!-- 当前显示的卡片 -->
    <div class="flashcard-wrapper" 
         ng-class="{ 
           'slide-out-right': flashCtrl.slideOutRight, 
           'slide-out-left': flashCtrl.slideOutLeft 
         }"
         ng-if="!flashCtrl.isNewCardActive">
      <div class="flashcard" 
           ng-class="{ flipped: flashCtrl.flashcards[flashCtrl.currentCardIndex].isFlipped }" 
           ng-click="flashCtrl.flipCard()">
        <div class="front" ng-show="!flashCtrl.flashcards[flashCtrl.currentCardIndex].isFlipped">
          <p>{{ flashCtrl.flashcards[flashCtrl.currentCardIndex].frontContent }}</p>
        </div>
        <div class="back" ng-show="flashCtrl.flashcards[flashCtrl.currentCardIndex].isFlipped">
          <p>{{ flashCtrl.flashcards[flashCtrl.currentCardIndex].backContent }}</p>
        </div>
      </div>
    </div>
    <!-- 即将进入的新卡片 -->
    <div class="flashcard-wrapper new-card" 
         ng-class="{ 
           'slide-in-left': flashCtrl.slideInLeft, 
           'slide-in-right': flashCtrl.slideInRight 
         }"
         ng-if="flashCtrl.isNewCardActive">
      <div class="flashcard" 
           ng-click="flashCtrl.flipCard()">
        <div class="front">
          <p>{{ flashCtrl.flashcards[flashCtrl.nextCardIndex].frontContent }}</p>
        </div>
        <div class="back">
          <p>{{ flashCtrl.flashcards[flashCtrl.nextCardIndex].backContent }}</p>
        </div>
      </div>
    </div>
  </div>
  <button class="navigation-btn next" ng-disabled="flashCtrl.currentCardIndex === flashCtrl.flashcards.length - 1" ng-click="flashCtrl.nextCard()">Next</button>
</div>

2. CSS样式调整

修改容器布局实现卡片重叠,新增双向滑入滑出的动画类:

body,
html {
  height: 100%;
  margin: 0;
  font-family: 'Arial', sans-serif;
  background-color: #f7f7f7;
  color: #444;
}

.flashcard-container {
  perspective: 1000px;
  width: 100%;
  height: 100%;
  display: flex;
  align-items: center;
  position: relative;
}

/* 新增视口容器,固定尺寸并允许内部卡片重叠 */
.flashcard-viewport {
  width: 50%;
  height: 60vh;
  margin: auto;
  position: relative;
  overflow: hidden;
}

.flashcard-wrapper {
  width: 100%;
  height: 100%;
  position: absolute;
  top: 0;
  left: 0;
  transition: transform 0.6s ease;
}

/* 新卡片初始位置在视口右侧外 */
.new-card {
  transform: translateX(150%);
}

.flashcard {
  width: 100%;
  height: 100%;
  border-radius: 15px;
  box-shadow: 0 10px 25px rgba(0, 0, 0, 0.1);
  background-color: #ffffff;
  border: 1px solid #e0e0e0;
  position: relative;
  transform-style: preserve-3d;
  cursor: pointer;
  user-select: none;
}

.flashcard,
.front,
.back {
  transition: transform 0.6s ease;
}

.flashcard.flipped {
  transform: rotateY(180deg);
}

.front,
.back {
  position: absolute;
  width: 100%;
  height: 100%;
  backface-visibility: hidden;
  border-radius: 15px;
  display: flex;
  justify-content: center;
  align-items: center;
  font-size: 24px;
  padding: 20px;
  box-sizing: border-box;
}

.back {
  transform: rotateY(180deg);
  background-color: #eeeeee;
}

.navigation-btn {
  padding: 10px 20px;
  margin: 20px;
  border: none;
  border-radius: 5px;
  background-color: #2c3e50;
  color: white;
  font-size: 16px;
  cursor: pointer;
  transition: background-color 0.3s ease;
  position: absolute;
  z-index: 2;
}

.navigation-btn.previous {
  left: 10px;
  top: 50%;
  transform: translateY(-50%);
}

.navigation-btn.next {
  right: 10px;
  top: 50%;
  transform: translateY(-50%);
}

/* 当前卡片滑出动画 */
.slide-out-right {
  transform: translateX(150%);
}

.slide-out-left {
  transform: translateX(-150%);
}

/* 新卡片滑入动画 */
.slide-in-left {
  transform: translateX(0);
}

.slide-in-right {
  transform: translateX(0);
}

3. 控制器逻辑更新

新增状态变量控制新卡片的显示和动画时序,确保双向动画同步执行:

var app = angular.module('flashcardApp', []);
app.controller('FlashcardController', function($scope, $timeout) {
  this.flashcards = [{
      frontContent: 'Front of Card 1',
      backContent: 'Back of Card 1',
      isFlipped: false
    },
    {
      frontContent: 'Front of Card 2',
      backContent: 'Back of Card 2',
      isFlipped: false
    },
    {
      frontContent: 'Front of Card 3',
      backContent: 'Back of Card 3',
      isFlipped: false
    },
    {
      frontContent: 'Front of Card 4',
      backContent: 'Back of Card 4',
      isFlipped: false
    }
  ];

  this.currentCardIndex = 0;
  this.nextCardIndex = 0; // 存储即将显示的卡片索引
  this.animating = false;
  this.isNewCardActive = false; // 控制新卡片是否显示
  this.slideOutRight = false;
  this.slideOutLeft = false;
  this.slideInLeft = false;
  this.slideInRight = false;

  this.flipCard = function() {
    if (!this.animating) {
      const activeIndex = this.isNewCardActive ? this.nextCardIndex : this.currentCardIndex;
      this.flashcards[activeIndex].isFlipped = !this.flashcards[activeIndex].isFlipped;
    }
  };

  this.nextCard = function() {
    if (this.currentCardIndex < this.flashcards.length - 1 && !this.animating) {
      this.animating = true;
      this.nextCardIndex = this.currentCardIndex + 1;
      this.isNewCardActive = true;
      // 触发当前卡片右滑出、新卡片左滑入的动画
      this.slideOutRight = true;
      this.slideInLeft = true;

      $timeout(() => {
        // 动画结束后更新状态
        this.slideOutRight = false;
        this.slideInLeft = false;
        this.currentCardIndex = this.nextCardIndex;
        this.isNewCardActive = false;
        // 切换后默认显示正面
        this.flashcards[this.currentCardIndex].isFlipped = false;
        $timeout(() => this.animating = false, 100);
      }, 600);
    }
  };

  this.previousCard = function() {
    if (this.currentCardIndex > 0 && !this.animating) {
      this.animating = true;
      this.nextCardIndex = this.currentCardIndex - 1;
      this.isNewCardActive = true;
      // 触发当前卡片左滑出、新卡片右滑入的动画
      this.slideOutLeft = true;
      this.slideInRight = true;

      $timeout(() => {
        // 动画结束后更新状态
        this.slideOutLeft = false;
        this.slideInRight = false;
        this.currentCardIndex = this.nextCardIndex;
        this.isNewCardActive = false;
        // 切换后默认显示正面
        this.flashcards[this.currentCardIndex].isFlipped = false;
        $timeout(() => this.animating = false, 100);
      }, 600);
    }
  };
});

关键改进点

  • 双卡片叠加布局,实现当前卡片滑出与新卡片滑入的同步动画
  • 拆分独立的动画状态变量,精准控制滑出/滑入方向
  • 严格的动画时序控制,避免内容切换与动画不同步导致的视觉错乱
  • 保留原卡片翻转功能,同时在切换时自动重置为正面显示

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 15:16:09