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

如何在React中实现组件切换时的平滑显隐动画?

实现组件切换的平滑淡入淡出动画

问题根源

你之前遇到的问题核心在于:当activeItem变化时,React会立即卸载旧组件并挂载新组件,导致旧组件的退出动画被中断;而CSS transition仅首次生效是因为后续切换时组件没有重新触发过渡条件(比如元素被直接移除而非样式变化)。

解决方案思路

要实现完整的"旧组件淡出→新组件淡入"效果,需要:

  1. 暂时保留旧组件在DOM中,直到其退出动画完成
  2. 让新旧组件在切换时重叠显示(避免布局跳动)
  3. 精确控制动画时序,确保旧组件动画结束后再卸载

完整实现代码

1. CSS动画定义

/* 容器样式:确保组件重叠 */
.content-container {
  position: relative;
  min-height: 400px; /* 根据你的内容高度调整 */
}

/* 组件基础样式:绝对定位实现重叠 */
.content-item {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
}

/* 淡出动画 */
.fade-out {
  animation: fadeOut 0.3s ease-out forwards;
}

/* 淡入动画 */
.fade-in {
  animation: fadeIn 0.3s ease-in forwards;
}

@keyframes fadeOut {
  from { opacity: 1; visibility: visible; }
  to { opacity: 0; visibility: hidden; }
}

@keyframes fadeIn {
  from { opacity: 0; visibility: hidden; }
  to { opacity: 1; visibility: visible; }
}

2. React组件逻辑修改

import { useState, useEffect } from 'react';

function YourParentComponent() {
  const [activeItem, setActiveItem] = useState('home');
  const [prevActiveItem, setPrevActiveItem] = useState(null);
  const [isTransitioning, setIsTransitioning] = useState(false);
  const ANIMATION_DURATION = 300; // 必须与CSS动画时长一致

  // 处理导航切换事件
  const switchContent = (newItem) => {
    if (newItem !== activeItem) {
      setIsTransitioning(true);
      setPrevActiveItem(activeItem);
      setActiveItem(newItem);
    }
  };

  // 动画结束后清理旧组件
  useEffect(() => {
    if (isTransitioning) {
      const timer = setTimeout(() => {
        setPrevActiveItem(null);
        setIsTransitioning(false);
      }, ANIMATION_DURATION);

      return () => clearTimeout(timer); // 组件卸载时清除定时器
    }
  }, [isTransitioning]);

  // 渲染对应组件的通用函数
  const renderContent = (item, isExiting) => {
    switch (item) {
      case "home":
        return <AppHome className={`content-item ${isExiting ? 'fade-out' : 'fade-in'}`} />;
      case "about-me":
        return <AppAboutMe className={`content-item ${isExiting ? 'fade-out' : 'fade-in'}`} />;
      default:
        return null;
    }
  };

  return (
    <div className="col-7 content-container">
      {/* 渲染旧组件(执行淡出动画) */}
      {prevActiveItem && renderContent(prevActiveItem, true)}
      {/* 渲染新组件(执行淡入动画) */}
      {renderContent(activeItem, false)}

      {/* 示例导航按钮 */}
      <div className="nav-buttons">
        <button onClick={() => switchContent('home')}>首页</button>
        <button onClick={() => switchContent('about-me')}>关于我</button>
      </div>
    </div>
  );
}

关键细节说明

  • 重叠布局:通过position: relative容器和position: absolute组件,让新旧组件在切换时完全重叠,避免页面跳动。
  • 时序控制:使用setTimeout等待动画完成后再卸载旧组件,确保淡出动画完整执行。
  • 防重复触发:isTransitioning状态防止用户快速点击时触发多个重叠的动画。
  • 动画一致性:ANIMATION_DURATION必须与CSS中定义的动画时长保持一致,否则会出现组件提前卸载或延迟消失的问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 20:30:43