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

React结合GSAP ScrollTrigger滚动动画仅首个区块生效问题求助

问题原因
  • 空依赖的useEffect执行时机早于列表DOM的完整渲染,只有第一个区块的ref在useEffect执行时已完成绑定,后续区块的ref.current为null,导致ScrollTrigger创建失败
  • 使用组件配置时,scrollTrigger的trigger参数直接传ID字符串的方式在列表循环渲染场景下会出现选择器匹配异常,导致只有第一个元素能触发动画
  • 预创建ref数组的写法不符合React循环渲染的ref绑定规范,容易出现ref引用丢失问题
修复方案

改用原生GSAP+回调ref的方案,代码更可控,修复后完整实现如下:

import React, { useRef, useEffect } from "react";
import { homeData } from "./homedata";
import classes from "./MainContainer.module.css";
import { gsap } from "gsap";
import { ScrollTrigger } from "gsap/dist/ScrollTrigger";
gsap.registerPlugin(ScrollTrigger);

const MainContainer = () => {
  const boxRef = useRef([]);
  // 每次重渲染前清空旧ref,避免残留无效DOM引用
  boxRef.current = [];

  useEffect(() => {
    // 清理已存在的ScrollTrigger实例,避免重复注册
    ScrollTrigger.getAll().forEach(trigger => trigger.kill());

    boxRef.current.forEach((el, index) => {
      // 跳过未完成绑定的元素
      if (!el) return;
      gsap.fromTo(
        el,
        { x: 0 },
        {
          x: "300px",
          duration: 2,
          ease: "bounce",
          scrollTrigger: {
            trigger: el,
            start: "top center+=100",
            // 可按需配置触发行为,当前配置为进入视口后仅播放一次
            toggleActions: "play none none none"
          }
        }
      );
    });
  // 依赖设为homeData长度,确保列表数据加载、DOM渲染完成后再初始化动画
  }, [homeData.length]);

  return (
    <section>
      {homeData.map((location, index) => {
        return (
          <section
            id={`section-${index}`}
            key={index}
            className={classes["home-section"]}
            style={{ background: `url(${location.image}) center/cover` }}
          >
            <div className={classes["left-side-main"]}>
              {/* 移除Tween组件,改用回调方式绑定ref */}
              <h1 
                ref={(el) => (boxRef.current[index] = el)} 
                id={`heading${index}`}
              >
                {location.location}
              </h1>
              <div className={classes["previous-next"]}>
                <button>Previous</button>
                <span></span>
                <button>Next</button>
              </div>
            </div>
            <div className={classes["right-side-main"]}>
              <p>{location.description}</p>
              <div className={classes["images-right-side"]}>
                <img src={location.moreImages[0]} alt="" />
                <img src={location.moreImages[1]} alt="" />
              </div>
            </div>
          </section>
        );
      })}
    </section>
  );
};

export default MainContainer;

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.02 14:54:03