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
相关产品推荐
相关产品推荐

