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

React TransitionGroup并行过渡问题:元素淡出与侧滑入不同步

解决React TransitionGroup中淡出与侧滑动画不同步的问题

我明白你想要的是旧元素淡出的同时新元素侧滑进入的同步过渡效果,现在的问题是TransitionGroup默认会等待旧元素完全退出后才挂载新元素,导致动画变成了顺序执行。咱们来一步步解决这个问题:

核心问题分析

你之前的写法是通过this.state.step === x来条件渲染对应的Transition组件,这意味着旧元素会在退出动画完成后被卸载,然后新元素才会被挂载并开始进入动画——这就是为什么你看到的是顺序执行的原因。虽然DevTools显示entered和exited状态同时触发,但DOM元素的挂载时机是滞后的,所以动画没法同步。

解决方案:让两个元素同时存在于DOM中

我们需要调整渲染逻辑,让两个Transition组件始终存在于DOM里,通过in属性来控制它们的进入/退出状态,而不是条件渲染。这样两个元素会重叠在同一空间,动画就能同步运行了。

修改后的代码示例

const duration = 500; // 统一动画时长,确保同步

const step1TransitionStyles = {
  entering: { opacity: 1 },
  entered: { opacity: 1 },
  exiting: { opacity: 0 },
  exited: { opacity: 0 }
};
const step2TransitionStyles = {
  entering: { transform: 'translateX(0)' },
  entered: { transform: 'translateX(0)' },
  exiting: { transform: 'translateX(100%)' },
  exited: { transform: 'translateX(100%)' }
};

// 组件内部
<div style={{ 
  position: 'fixed', 
  top: 0, 
  right: 0, 
  height: 400, 
  width: 400, 
  zIndex: 10, 
  backgroundColor: '#ccc',
  // 确保子元素绝对定位时能正确对齐
  position: 'relative' 
}} >
  <TransitionGroup appear={true}>
    {/* Step 1 始终渲染,通过in控制显示/隐藏 */}
    <Transition key='1' in={this.state.step === 1} timeout={duration}>
      {(state) => (
        <div style={{ 
          transition: `opacity ${duration}ms ease-in-out`, 
          // 初始状态设为透明,避免首次渲染闪烁
          opacity: 0, 
          backgroundColor: '#8787d8', 
          position: 'absolute', 
          top: 0, 
          left: 0, 
          bottom: 0, 
          right: 0,
          // 退出时z-index降低,避免遮挡新元素
          zIndex: state === 'exiting' ? 1 : 2,
          ...step1TransitionStyles[state] 
        }}>
          Step #1 <br />
          <button onClick={this.handleStep1Next}>Next</button>
        </div>
      )}
    </Transition>

    {/* Step 2 始终渲染,通过in控制显示/隐藏 */}
    <Transition key='2' in={this.state.step === 2} timeout={duration}>
      {(state) => (
        <div style={{ 
          transition: `transform ${duration}ms ease-in-out`, 
          backgroundColor: '#8787d8', 
          position: 'absolute', 
          top: 0, 
          left: 0, 
          bottom: 0, 
          right: 0,
          // 进入时z-index更高,覆盖旧元素
          zIndex: state === 'entering' || state === 'entered' ? 2 : 1,
          ...step2TransitionStyles[state] 
        }}>
          Step #2 <br />
          <button onClick={this.handleStep2Back}>Back</button>
        </div>
      )}
    </Transition>
  </TransitionGroup>
</div>

关键调整点说明

  • 取消条件渲染:两个Transition组件始终被渲染,通过in={this.state.step === x}来控制它们的进入/退出状态,这样两个元素会同时存在于DOM中。
  • z-index控制层级:给进入的元素设置更高的z-index,避免被退出的元素遮挡,保证视觉效果正确。
  • 统一动画时长:确保两个动画的duration一致,这样同步性会更好。
  • 调整初始状态:Step1的初始opacity设为0,避免首次渲染时的闪烁问题;Step2的初始transform设为translateX(100%)(在exited状态中定义),确保进入前处于屏幕外。

这样修改后,当你点击Next/Back按钮切换step时,旧元素会开始淡出,同时新元素会开始侧滑进入,两者的动画就完全同步了。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 08:09:14