reactjs 使用react和gsap的简单动画

sz81bmfz  于 2023-02-18  发布在  React
关注(0)|答案(1)|浏览(571)

我已经为此纠结了好几天了,我只是很难理解各种各样的文档和例子,所以我希望有人能帮助我解决我正在研究的具体例子,这可能反过来会帮助我更好地理解这一点。这看起来比它应该的要复杂得多,但我相信这只是我对它是如何工作的缺乏理解。
我们的目标是:制作一个非常简单的红球来回移动的动画。见鬼,制作任何类型的动画(一旦我能确认gsap正在制作任何东西的动画,我应该可以从那里开始)。
问题是:什么都没发生。没有错误,没有什么可以继续的,什么都没有。我仍然没有一个很强的理解这应该如何工作;我查过的许多指南似乎都使用了不同的方法,并且没有详细说明原因,因此很难将这些知识扩展到我的特定场景。
代码。我已经大大简化了这个,因为,正如我提到的,我真正需要的只是让任何一种gsap动画工作,从那里我有信心我可以用它来做我需要的。如果有人觉得它会有所作为,我很乐意更新完整的代码:

import React, { useRef, useEffect } from 'react';
import { gsap } from 'gsap';

const tl = gsap.timeline({paused: true, repeat: 0});

function App() {

  const waitingAnimationRef = useRef(null);

  useEffect(() => {
    tl.set(waitingAnimationRef, {autoAlpha: 0});
    tl.play();
  }, []);

  return (
    <div className="App">
      <div id="red-circle" ref={waitingAnimationRef}></div>
    </div>
  );
}

export default App;
mzsu5hc0

mzsu5hc01#

下面是一个可以正常工作的example以及一些帮助您理解它的提示:
1.用gasp.timeline创建一个时间轴,并将其存储在一个ref中。您可以像之前一样在组件外部创建时间轴,但随后需要将该时间轴传递给组件中的ref。在本例中,我将时间轴的变量名直接传递给useRef钩子:const tl = useRef(timeline);.
1.我使用了时间轴选项{ repeat: -1, yoyo: true },这样动画就会在交替的方向上无限循环,因为你说过你想让一个球"来回移动"。
1.您还需要一个DOM节点ref,以便将其传递给gsap.context()方法。在组件中创建ref并将其传递给组件的 Package 元素。我调用了我的应用程序(const app = useRef(null)),然后使用ref={app}将其传递给App组件中的顶级div。请确保将ref传递给DOM节点,而不是React组件(或者你必须把ref向下转发到它里面的一个节点子节点)。我们为什么要使用refs?因为refs在你的组件的重渲染之间是稳定的,比如state,但是不像state,修改refs不会导致重渲染。useRef钩子返回一个带有一个名为current的属性的对象。无论你在ref中放入什么,都可以通过current属性访问。
1.使用useLayoutEffect()钩子而不是useEffect。React保证useLayoutEffect内的代码和其中安排的任何状态更新将在浏览器重绘屏幕之前得到处理。useEffect钩子不会阻止浏览器重绘。大多数时候,我们希望这样做,这样我们的应用就不会变慢。然而,在这种情况下,useLayoutEffect钩子确保React已经执行了所有的DOM变化,并且gsap可以访问这些元素来使它们具有动画效果。
1.在useLayoutEffect中,你将使用gsap context方法。gsap context方法有两个参数:一个回调函数和一个组件引用。回调函数是你可以访问时间线的地方(别忘了通过ref对象的current属性访问)和运行动画的地方。
1.有两种方法可以定位要在时间线上设置动画的元素:要么使用ref来存储DOM节点,要么通过选择器。我使用".box"类的选择器来存储box元素。这很简单,也很好,因为它只会选择当前组件的子元素。我使用ref来存储circle组件。我将其作为示例包括在内,因此,您可以看到如何使用forwardRefs将ref从App组件通过Circle组件传递到div DOM子节点。尽管这是一种更"类似于React"的方法,但如果要对许多元素进行动画处理,则会更加困难,灵活性也更低。
1.就像useEffect一样,useLayoutEffect返回一个clean up函数,方便的是,gsap上下文对象有一个名为revert的clean up方法。

import { useLayoutEffect, useRef } from "react";
import gsap from "gsap";

const timeline = gsap.timeline({ repeat: -1, yoyo: true });

function App() {
  const tl = useRef(timeline);
  const app = useRef(null);
  const circle = useRef(null);

  useLayoutEffect(() => {
    const ctx = gsap.context(() => {
      tl.current
        // use scoped selectors
        // i.e., selects matching children only
        .to(".box", {
          rotation: 360,
          borderRadius: 0,
          x: 100,
          y: 100,
          scale: 1.5,
          duration: 1
        })
        // or refs
        .to(circle.current, {
          rotation: 360,
          borderRadius: 50,
          x: -100,
          y: -100,
          scale: 1.5,
          duration: 1
        });
    }, app.current);

    return () => ctx.revert();
  }, []);

  return (
    <div ref={app} className="App">
      <Box />
      <Circle ref={circle} />
    </div>
  );
}

相关问题