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

React实现顶部新增列表项时的平滑滚动动画方案

问题描述

我通过Socket逐个接收元素并添加到列表中,规则是:

  • 新元素添加到列表顶部
  • 同时删除列表的最后一个元素

初始列表状态:

  • Element 1
  • Element 2
  • Element 3
  • Element 4

添加Element 5后的状态:

  • Element 5
  • Element 1
  • Element 2
  • Element 3

想要实现的动画效果:

  1. 新元素从顶部平滑滑入
  2. 原有中间元素(如Element 2、3)平滑下移
  3. 最后一个元素完全透明并滑出消失

我尝试用react-transition-group实现,但仅首尾元素有动画,中间元素直接跳转到新位置,无平滑过渡。代码如下:

模板代码

<TransitionGroup className="list">
  {
    list.map((item) => {
      return (
        <CSSTransition 
               key={item.id} 
               classNames="list-item" 
               timeout={500}>
          <div key={item.id}>Элемент {item.id}</div>
        </CSSTransition>
      );
    })
 }
</TransitionGroup>

样式代码

.list-item-enter {
  opacity: 0;
  transform: translateY(-100%);
  transition: opacity 500ms, transform 500ms;
}

.list-item-enter-done {
  opacity: 1;
  transform: translateY(0%);
}

.list-item-exit {
  opacity: 1;
  transform: translateY(0%);
  transition: opacity 500ms, transform 500ms;
}

.list-item-exit-active {
  opacity: 0;
  transform: translateY(100%);
}

请问有其他实现该动画的方法吗?


解决方案

方法1:CSS Flex + 自定义位置过渡(无需额外库)

核心思路是给列表容器固定高度,让每个列表项的位置变化通过transform过渡,同时结合react-transition-group处理首尾元素的进入/退出动画。

  1. 调整列表容器与项的基础样式:
/* 固定容器高度,刚好容纳4个列表项(假设每个项高40px) */
.list {
  height: calc(4 * 40px);
  overflow: hidden;
  display: flex;
  flex-direction: column;
}

.list-item {
  height: 40px;
  /* 给位置变化添加过渡动画 */
  transition: transform 500ms ease;
}
  1. 修改渲染逻辑,给每个项计算位移值:
<TransitionGroup className="list">
  {list.map((item, index) => {
    // 新元素加入后,原有元素会下移一个项的高度,计算对应位移
    const translateY = index * 40;
    return (
      <CSSTransition key={item.id} classNames="list-item" timeout={500}>
        <div 
          className="list-item"
          style={{ transform: `translateY(${translateY}px)` }}
        >
          Элемент {item.id}
        </div>
      </CSSTransition>
    );
  })}
</TransitionGroup>
  1. 优化进入/退出的CSS动画:
.list-item-enter {
  opacity: 0;
  transform: translateY(-40px); /* 从容器上方滑入 */
}

.list-item-enter-active {
  opacity: 1;
  transform: translateY(0);
}

.list-item-exit {
  opacity: 1;
  transform: translateY(0);
}

.list-item-exit-active {
  opacity: 0;
  transform: translateY(40px); /* 滑出容器下方 */
}

方法2:用react-spring实现更流畅的过渡

react-spring可以自动处理元素的位置和透明度过渡,无需手动计算位移:

  1. 安装依赖:
npm install react-spring
  1. 实现动画列表组件:
import { useTransition, animated } from 'react-spring';

function AnimatedList({ list }) {
  const transitions = useTransition(list, {
    key: item => item.id,
    from: { opacity: 0, transform: 'translateY(-40px)' },
    enter: { opacity: 1, transform: 'translateY(0)' },
    leave: { opacity: 0, transform: 'translateY(40px)' },
    trail: 100, // 元素依次动画的延迟,增强滚动感
  });

  return (
    <div className="list">
      {transitions((style, item) => (
        <animated.div style={style} className="list-item">
          Элемент {item.id}
        </animated.div>
      ))}
    </div>
  );
}
  1. 基础样式:
.list {
  height: calc(4 * 40px);
  overflow: hidden;
  display: flex;
  flex-direction: column;
}

.list-item {
  height: 40px;
}

关键原理说明

之前用react-transition-group失效的原因是:中间元素的key未变化,React只会更新它们的位置,不会触发进入/退出动画。上面的方法通过:

  • 给列表项的transform属性添加过渡,让位置变化平滑
  • 结合进入/退出动画处理首尾元素的滑入滑出
  • react-spring则通过内部状态管理,自动处理所有元素的过渡效果

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 09:23:09