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

React中用GSAP实现翻书滚动动画遇.getContext错误求助

解决React中Canvas关联GSAP时的.getContext is not a function错误

核心问题分析

  • React的useRef返回的是Ref对象,你直接操作canvasRef而非其current属性,而current才指向实际的Canvas DOM元素
  • 在组件渲染阶段直接初始化Canvas,此时Canvas还未挂载到DOM树,canvasRef.current为null,自然无法调用getContext
  • 代码中currentFrame箭头函数存在语法错误,把=>写成了=

修复步骤

  1. 使用useEffect钩子,在组件挂载后再操作Canvas DOM元素
  2. 所有操作Canvas的逻辑都要通过canvasRef.current访问真实DOM节点
  3. 修正currentFrame的语法错误
  4. 集成GSAP ScrollTrigger实现滚动控制帧动画的逻辑

修复后的完整代码

import { useRef, useEffect } from "react";
import gsap from "gsap";
import ScrollTrigger from "gsap/ScrollTrigger";

// 注册ScrollTrigger插件
gsap.registerPlugin(ScrollTrigger);

function Landing() {
  const canvasRef = useRef(null);
  const frameCount = 230;

  const currentFrame = (index) => 
    `../../assets/landing-animations/${(index + 1).toString()}.jpg`;

  useEffect(() => {
    // 确保Canvas DOM元素存在
    const canvas = canvasRef.current;
    if (!canvas) return;

    // 初始化Canvas尺寸
    canvas.width = window.innerWidth;
    canvas.height = window.innerHeight;
    const context = canvas.getContext("2d");
    const images = [];
    let animationState = { frame: 0 };

    // 预加载所有帧图片
    for (let i = 0; i < frameCount; i++) {
      const img = new Image();
      img.src = currentFrame(i);
      images.push(img);
    }

    // 渲染函数
    function render() {
      context.clearRect(0, 0, canvas.width, canvas.height);
      context.drawImage(images[animationState.frame], 0, 0);
    }

    // 第一帧加载完成后初始化渲染
    images[0].onload = () => {
      render();

      // 用GSAP ScrollTrigger实现滚动控制动画
      gsap.to(animationState, {
        frame: frameCount - 1,
        snap: "frame",
        ease: "none",
        scrollTrigger: {
          trigger: canvas,
          scrub: 0.5, // 滚动与动画的同步系数
          start: "top top",
          end: "bottom bottom",
          // 可选:添加标记方便调试
          // markers: true
        },
        onUpdate: render // 每帧更新时调用渲染
      });
    };

    // 窗口 resize 时重新设置Canvas尺寸
    const handleResize = () => {
      canvas.width = window.innerWidth;
      canvas.height = window.innerHeight;
      render();
    };
    window.addEventListener("resize", handleResize);

    // 清理函数:移除监听和销毁ScrollTrigger
    return () => {
      window.removeEventListener("resize", handleResize);
      ScrollTrigger.getAll().forEach(trigger => trigger.kill());
    };
  }, []);

  return (
    <div className="landing">
      <h1 className="landing__header">Welcome to my portfolio</h1>
      <canvas className="landing__canvas" ref={canvasRef}></canvas>
    </div>
  );
}

export default Landing;

额外说明

  • 必须注册ScrollTrigger插件才能使用其功能
  • 添加了窗口resize监听,保证Canvas尺寸适配窗口变化
  • 通过onUpdate钩子绑定渲染函数,实现帧动画随滚动更新
  • 清理函数中销毁ScrollTrigger和移除监听,避免内存泄漏

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 18:50:32