如何为React中从对象动态渲染的幻灯片添加进入退出CSS过渡效果
React幻灯片添加进入/退出过渡的最优实现方案
核心问题:你现有代码直接切换currentSlide时,旧幻灯片DOM会被立即卸载,没有预留过渡动画的执行时间,这是手动加类名方案不达预期的根本原因。
方案1:使用react-transition-group(生产环境推荐,无需手动处理DOM生命周期)
这是该场景下最稳定的实现方案,不用自己维护过渡时序,代码可维护性更高。
实现步骤
- 先修正你
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" } }
- 安装依赖:
npm install react-transition-group
- 组件代码修改:
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> ); };
- 配套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
相关产品推荐
相关产品推荐

