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

如何在使用React useState切换img src时添加过渡效果?

解决React切换图片src时添加过渡效果的问题

直接给<img>元素加CSS transition不生效的核心原因是:切换src本质是替换图片资源,不属于CSS可过渡的属性变化,浏览器无法对资源替换过程应用过渡动画。下面是几种可行的解决方案:

方法一:双图片叠加+透明度过渡

这是最常用的无依赖方案,通过两张图片叠加在同一容器中,切换它们的透明度来实现淡入淡出效果。

步骤1:编写CSS样式

.image-wrapper {
  position: relative;
  /* 根据你的图片尺寸设置宽高 */
  width: 600px;
  height: 400px;
}

.image-wrapper img {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  object-fit: cover; /* 保持图片比例,适配容器 */
  transition: opacity 0.6s ease; /* 定义过渡动画 */
}

/* 隐藏状态的图片 */
.image-wrapper .img-hidden {
  opacity: 0;
  visibility: hidden; /* 让隐藏的图片不响应交互 */
}

步骤2:修改React组件

import { useState } from 'react';
import image1 from './assets/image1.jpg';
import image2 from './assets/image2.jpg';

export default function ImageSwitch() {
  const [activeIndex, setActiveIndex] = useState(0);
  const images = [image1, image2];

  return (
    <div>
      <button onClick={() => setActiveIndex(prev => prev === 0 ? 1 : 0)}>
        切换图片
      </button>
      <div className="image-wrapper">
        {/* 第一张图片:根据索引控制显示/隐藏 */}
        <img
          src={images[0]}
          alt="图1"
          className={activeIndex === 1 ? 'img-hidden' : ''}
        />
        {/* 第二张图片:同理 */}
        <img
          src={images[1]}
          alt="图2"
          className={activeIndex === 0 ? 'img-hidden' : ''}
        />
      </div>
    </div>
  );
}

方法二:使用背景图容器切换

如果不想在DOM中保留两张图片,可以将图片作为容器的背景图,通过切换容器的背景属性并配合过渡:

CSS样式

.bg-image-container {
  position: relative;
  width: 600px;
  height: 400px;
  transition: opacity 0.5s ease;
}

.bg-image-container::before {
  content: '';
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background-size: cover;
  background-position: center;
  transition: opacity 0.5s ease;
}

.bg-image-container.active-1::before {
  background-image: url('./assets/image1.jpg');
  opacity: 1;
}

.bg-image-container.active-2::before {
  background-image: url('./assets/image2.jpg');
  opacity: 1;
}

React组件

import { useState } from 'react';

export default function BgImageSwitch() {
  const [activeClass, setActiveClass] = useState('active-1');

  return (
    <div>
      <button onClick={() => setActiveClass(prev => prev === 'active-1' ? 'active-2' : 'active-1')}>
        切换背景图
      </button>
      <div className={`bg-image-container ${activeClass}`}></div>
    </div>
  );
}

方法三:借助React Transition Group库(需额外依赖)

如果项目已经使用动画库,可以用react-transition-group简化动画逻辑:

  1. 先安装依赖:
npm install react-transition-group
  1. 组件实现:
import { useState } from 'react';
import { CSSTransition } from 'react-transition-group';
import image1 from './assets/image1.jpg';
import image2 from './assets/image2.jpg';

export default function TransitionImageSwitch() {
  const [showImage1, setShowImage1] = useState(true);

  return (
    <div style={{position: 'relative', width: '600px', height: '400px'}}>
      <button onClick={() => setShowImage1(prev => !prev)}>切换图片</button>
      
      <CSSTransition
        in={showImage1}
        timeout={500}
        classNames="img-transition"
        unmountOnExit
      >
        <img src={image1} alt="图1" style={{position: 'absolute', top:0, left:0, width:'100%', height:'100%', objectFit:'cover'}} />
      </CSSTransition>
      
      <CSSTransition
        in={!showImage1}
        timeout={500}
        classNames="img-transition"
        unmountOnExit
      >
        <img src={image2} alt="图2" style={{position: 'absolute', top:0, left:0, width:'100%', height:'100%', objectFit:'cover'}} />
      </CSSTransition>
    </div>
  );
}
  1. 对应的CSS:
.img-transition-enter {
  opacity: 0;
}
.img-transition-enter-active {
  opacity: 1;
  transition: opacity 500ms ease-in-out;
}
.img-transition-exit {
  opacity: 1;
}
.img-transition-exit-active {
  opacity: 0;
  transition: opacity 500ms ease-in-out;
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 20:47:26