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

如何为React中从对象动态渲染的幻灯片添加进入退出CSS过渡效果

React幻灯片添加进入/退出过渡的最优实现方案

核心问题:你现有代码直接切换currentSlide时,旧幻灯片DOM会被立即卸载,没有预留过渡动画的执行时间,这是手动加类名方案不达预期的根本原因。

方案1:使用react-transition-group(生产环境推荐,无需手动处理DOM生命周期)

这是该场景下最稳定的实现方案,不用自己维护过渡时序,代码可维护性更高。

实现步骤

  1. 先修正你slides对象的定义问题:原有nextSlide/prevSlide直接写变量名会触发引用错误,改为对应幻灯片的key字符串:
const slides = {
  slide1: {
    id: 1,
    content: <>Slide 1 content</>,
    nextSlide: "slide2",
    prevSlide: null
  },
  slide2: {
    id: 2,
    content: <>Slide 2 content</>,
    nextSlide: "slide3",
    prevSlide: "slide1",
  },
  slide3: {
    id: 3,
    content: <>Slide 3 content</>,
    nextSlide: null,
    prevSlide: "slide2"
  }
}
  1. 安装依赖:
npm install react-transition-group
  1. 组件代码修改:
import { useState } from 'react';
import { CSSTransition, TransitionGroup } from 'react-transition-group';

const SlideComponent = () => {
  const [currentSlide, setCurrentSlide] = useState("slide1");
  const currentSlideData = slides[currentSlide];

  return (
    <div className="slide-container">
      <TransitionGroup>
        <CSSTransition
          key={currentSlideData.id} // key变化时触发过渡
          timeout={300} // 过渡时长要和CSS里的duration保持一致
          classNames="slide"
        >
          <div className="slide-content">
            {currentSlideData.content}
          </div>
        </CSSTransition>
      </TransitionGroup>
      
      <div className="slide-controls">
        <button 
          disabled={!currentSlideData.prevSlide}
          onClick={() => setCurrentSlide(currentSlideData.prevSlide)}
        >
          Previous Slide
        </button>
        <button 
          disabled={!currentSlideData.nextSlide}
          onClick={() => setCurrentSlide(currentSlideData.nextSlide)}
        >
          Next Slide
        </button>
      </div>
    </div>
  );
};
  1. 配套CSS样式:
.slide-container {
  position: relative;
  overflow: hidden;
  width: 100%;
  min-height: 300px;
}

.slide-content {
  width: 100%;
  height: 100%;
  position: absolute;
  top: 0;
  left: 0;
}

/* 进入动画开始状态 */
.slide-enter {
  opacity: 0;
  transform: translateX(100%);
}
/* 进入动画执行中 */
.slide-enter-active {
  opacity: 1;
  transform: translateX(0);
  transition: all 300ms ease-in-out;
}
/* 退出动画开始状态 */
.slide-exit {
  opacity: 1;
  transform: translateX(0);
}
/* 退出动画执行中 */
.slide-exit-active {
  opacity: 0;
  transform: translateX(-100%);
  transition: all 300ms ease-in-out;
}

如果你需要向前切换时动画方向反过来,可以额外加一个状态记录切换方向,动态修改classNames的前缀即可。

方案2:纯原生实现(无第三方依赖)

如果不想引入额外依赖,可以手动维护过渡状态,核心逻辑是切换幻灯片时先保留旧DOM,等退出过渡执行完成后再卸载:

import { useState, useRef, useEffect } from 'react';

const SlideComponent = () => {
  const [currentSlide, setCurrentSlide] = useState("slide1");
  const [prevSlide, setPrevSlide] = useState(null);
  const [isTransitioning, setIsTransitioning] = useState(false);
  const transitionTimer = useRef(null);

  const handleSlideChange = (targetSlide) => {
    if (isTransitioning || !targetSlide) return;
    // 先记录旧幻灯片,触发退出过渡
    setPrevSlide(currentSlide);
    setIsTransitioning(true);
    // 等过渡时长到了之后清除旧幻灯片,重置状态
    transitionTimer.current = setTimeout(() => {
      setPrevSlide(null);
      setIsTransitioning(false);
    }, 300);
    // 更新当前幻灯片,触发进入过渡
    setCurrentSlide(targetSlide);
  };

  useEffect(() => {
    return () => clearTimeout(transitionTimer.current);
  }, []);

  return (
    <div className="slide-container">
      <div className="slide-content">
        {prevSlide && <div className="slide-exit">{slides[prevSlide].content}</div>}
        <div className="slide-enter">{slides[currentSlide].content}</div>
      </div>
      <button 
        disabled={!slides[currentSlide].prevSlide || isTransitioning}
        onClick={() => handleSlideChange(slides[currentSlide].prevSlide)}
      >
        Previous Slide
      </button>
      <button 
        disabled={!slides[currentSlide].nextSlide || isTransitioning}
        onClick={() => handleSlideChange(slides[currentSlide].nextSlide)}
      >
        Next Slide
      </button>
    </div>
  )
}

配套CSS和方案1基本一致,把slide-enter/slide-exit对应的样式直接绑定到对应类名即可。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.27 15:54:06