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

如何实现react-spring动画仅在组件进入用户可视视口时触发

解决方法

问题根源

你当前的控制逻辑失效,核心原因是useTransition会在组件首次渲染时就基于传入的items初始化动画序列,即使你通过appear变量控制DOM渲染,动画的时间线已经在页面加载时就启动了,并不会等到DOM渲染时再重新触发。

具体实现步骤

1. 用Intersection Observer监听组件是否进入视口

这是浏览器原生提供的高性能滚动监听API,不需要自己绑定scroll事件计算位置,兼容性覆盖绝大多数现代浏览器。

2. 调整react-spring的触发逻辑

仅当组件进入视口时,才给useTransition传入完整的渲染列表,让动画在此时才开始初始化执行。

修改后完整代码

import { useRef, useEffect, useState } from 'react';
import { useTransition, animated, config } from 'react-spring';
// 你的Container、Row、Col组件按原有逻辑正常引入即可

const cols = [
/*Components here that will be animated ..*/
{component: <div><p>A</p></div> , key:1},
{component: <div><p>B</p></div> , key:2},
{component: <div><p>C</p></div> , key:3},
]

export default function Foocomponent(){
  // 给容器绑定ref,用于监听可见性
  const containerRef = useRef(null);
  const [appear, setAppear] = useState(false);
  // 初始状态下items为空,不会触发动画
  const [items, setItems] = useState([]);

  const transitions = useTransition(items, (item) => item.key, {
    from: { opacity: 0, transform: 'translateY(70px) scale(0.5)', borderRadius: '0px' },
    enter: { opacity: 1, transform: 'translateY(0px) scale(1)', borderRadius: '20px', border: '1px solid #00b8d8' },
    delay: 200,
    config: config.molasses,
  })

  // 监听容器可见性
  useEffect(() => {
    const observer = new IntersectionObserver(
      (entries) => {
        const [entry] = entries;
        if (entry.isIntersecting && !appear) {
          setAppear(true);
          // 组件进入视口后,再设置要渲染的列表,触发动画
          setItems(cols);
          // 如果不需要重复触发,此时可以取消监听节约性能
          observer.unobserve(entry.target);
        }
      },
      { threshold: 0.1 } // 10%的内容进入视口就触发,可自行调整阈值
    );
    if (containerRef.current) {
      observer.observe(containerRef.current);
    }
    return () => {
      if (containerRef.current) observer.unobserve(containerRef.current);
    };
  }, [appear]);

  return (
        <Container ref={containerRef}>
          <Row>
            {transitions.map(({ item, props, key }) => (
              <Col className="feature-item">
                <animated.div key={key} style={props} >
                  {item.component}
                </animated.div>
              </Col>
            ))}
          </Row>
        </Container>
  );
}

额外说明

如果需要组件每次进入视口都重新触发动画,可以去掉observer.unobserve的逻辑,同时在组件离开视口时把items设为空数组即可。

内容的提问来源于stack exchange,提问作者John C.

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.06 01:24:03