使用 React Hooks 和 GreenSock 实现动画

2025-05-25

使用 React Hooks 和 GreenSock 实现动画

作者:Paul Ryan✏️

探索 Web 动画的世界,既可以是一段精彩的旅程,也可以是一段令人疲惫的旅程。我的目标是让它成为一段精彩的旅程,同时利用 React Hooks 的强大功能进一步提升你的学习体验。

我需要知道什么?

本文不应被视为 JavaScript 或 React 的入门指南。我将逐一解释我们使用到的概念,但您至少应该对两者都有一定了解。您可以点击此处查看 React 文档

LogRocket 免费试用横幅

我们将要创造什么?

我喜欢以身作则。光是把一堆概念和文字塞给你,对你的学习没有任何帮助,而且说实话,这对我们俩来说都会很枯燥。我们将制作两个独立的动画,每个动画的难度都会逐渐增加。

我们的第一个动画将是一个简单的加载器,类似于谷歌的:

完成动画加载器

我们的第二个目标是将 LogRocket 徽标制作成动画,使其变得更好!

LogRocket 标志

开始设置

设置快捷简单:我在这里创建了一个 CodeSandbox,它有 GreenSock npm 模块,也有 React,所以您只需分叉它并继续操作即可。

Google 风格的加载器

现在我们可以开始创建Loader组件了。如果你能跟着我一起做就更好了,不过最后我会附上完整的 CodeSandbox 链接。

我们的加载器首先需要的是图形,我已经创建好了。SVG 是一个基础的 SVG,只包含一些标记。

<svg viewBox="0 0 150 33.2" width="180" height="150">
  <circle ref={circle} cx="16.1" cy="16.6" r="16.1" fill="#527abd" />
  <circle ref={circle} cx="55.2" cy="16.6" r="16.1" fill="#de4431" />
  <circle ref={circle} cx="94.3" cy="16.6" r="16.1" fill="#f4b61a" />
  <circle ref={circle} cx="133.4" cy="16.6" r="16.1" fill="#009e52" />
</svg>
Enter fullscreen mode Exit fullscreen mode

然后,在我们的源代码中,我们可以创建一个Loader组件,这就是奇迹发生的地方。

在组件内部Loader,我们想要渲染我们的图形。

// src/loader.jsx
import React from "react";
const Loader = () => {
  return (
    <svg viewBox="0 0 150 33.2" width="180" height="150">
      <circle cx="16.1" cy="16.6" r="16.1" fill="#527abd" />
      <circle cx="55.2" cy="16.6" r="16.1" fill="#de4431" />
      <circle cx="94.3" cy="16.6" r="16.1" fill="#f4b61a" />
      <circle cx="133.4" cy="16.6" r="16.1" fill="#009e52" />
    </svg>
  );
};
export default Loader;
Enter fullscreen mode Exit fullscreen mode

您现在应该看到:

静态加载器 SVG

太棒了!现在图形已经制作好了,接下来我们来制作动画吧。

动画制作时,首先需要的是要制作动画的元素的引用。为了获取元素的引用,我们可以使用useRefHook。useRef它会返回一个 ref 对象,该对象包含一个current属性,而这正是动画的目标。

创建useRef很简单:

const myElement = useRef(null) 
Enter fullscreen mode Exit fullscreen mode

因此,对于我们的情况,我们需要定位四个元素。我们将创建四个引用,如下所示:

const blue = useRef(null);
const red = useRef(null);
const yellow = useRef(null);
const green = useRef(null);
Enter fullscreen mode Exit fullscreen mode

然后我们可以将这些引用添加到我们的 SVG 中:

<svg viewBox="0 0 150 33.2" width="180" height="150">
  <circle ref={blue} cx="16.1" cy="16.6" r="16.1" fill="#527abd" />
  <circle ref={red} cx="55.2" cy="16.6" r="16.1" fill="#de4431" />
  <circle ref={yellow} cx="94.3" cy="16.6" r="16.1" fill="#f4b61a" />
  <circle ref={green} cx="133.4" cy="16.6" r="16.1" fill="#009e52" />
</svg>
Enter fullscreen mode Exit fullscreen mode

我们的组件现在看起来像这样:

// src/loader.jsx
import React, { useRef } from "react";

const Loader = () => {
  const blue = useRef(null);
  const red = useRef(null);
  const yellow = useRef(null);
  const green = useRef(null);

  return (
    <svg viewBox="0 0 150 33.2" width="180" height="150">
      <circle ref={blue} cx="16.1" cy="16.6" r="16.1" fill="#527abd" />
      <circle ref={red} cx="55.2" cy="16.6" r="16.1" fill="#de4431" />
      <circle ref={yellow} cx="94.3" cy="16.6" r="16.1" fill="#f4b61a" />
      <circle ref={green} cx="133.4" cy="16.6" r="16.1" fill="#009e52" />
    </svg>
  );
};

export default Loader;
Enter fullscreen mode Exit fullscreen mode

一切就绪后,我们就可以开始使用 GreenSock 了。

首先我们导入TweenMax

import { TweenMax } from "gsap";
Enter fullscreen mode Exit fullscreen mode

TweenMax 是 GreenSock 的一个功能齐全的模块,可以帮助我们创建动画。它有很多方法,我们将使用其中几个!

GreenSock 还为我们提供了 TweenLite,这是一个功能较少但更轻量级的模块。

对于动画,我们希望它在组件挂载时发生。在传统的基于类的组件中,我们会使用componentDidMount,但对于 Hooks,我们将使用useEffect,它的行为与 Hooks 相同,但有一些细微的差别。想要深入了解 Hooks,你应该看看 Dan Abramov 的这篇精彩文章

因此,当我们的组件挂载时,我们将使用 TweenMax 的fromTo方法来为圆圈添加动画。该fromTo方法传递了四个参数:

fromTo(element(s), duration, start, end)
Enter fullscreen mode Exit fullscreen mode

让我们集中精力让blue圆圈上下移动。为此,我们将瞄准y动画的属性。

因此我们的代码如下:

TweenMax.fromTo(blue.current, 5, { y: 18 }, { y: -18 });
Enter fullscreen mode Exit fullscreen mode

我们首先定位元素,然后设置持续时间5s。我们从y位置开始18,到 结束-18。如下所示:

蓝圈动画

好的,我们取得了一些进展,但仍然存在一些问题——速度太慢,而且我们还需要动画无限循环。让我们解决这些问题。为此,我们需要做的就是在对象中添加yoyorepeat属性to

TweenMax.fromTo(blue.current, 0.5, { y: 18 }, { y: -18, yoyo: true, repeat: -1 });
Enter fullscreen mode Exit fullscreen mode

yoyo表示动画将yoyo在起始位置和结束位置之间移动。设置repeat-1将使动画无限循环。我们还将持续时间设置为半秒,这样速度会更快。

现在,随着我们新房产的到位,我们拥有:

蓝圈动画

从上面完成的动画中可以看到,黄色圆圈的行为与蓝色圆圈相同。考虑到这一点,我们可以将一个元素数组(ourblueyellowref)传递给我们的fromTo方法。

TweenMax.fromTo(
  [blue.current, yellow.current],
  0.5,
  { y: 18 },
  { y: -18, yoyo: true, repeat: -1 }
);
Enter fullscreen mode Exit fullscreen mode

所以现在我们有:

蓝色和黄色圆圈弹跳

成功了!我想你现在应该能感受到 GreenSock 的强大了。为了完成动画,我们只需要将红球和绿球以相反的方式动画起来,如下所示:

TweenMax.fromTo(
  [red.current, green.current],
  0.5,
  { y: -18 },
  { y: 18, repeat: -1, yoyo: true }
);
Enter fullscreen mode Exit fullscreen mode

这段代码几乎和上面的代码完全相同,只是这次我们从 开始y:-18,从 结束y:18

我们的最终动画现已完成,它看起来应该是这样的:

完成动画加载器

完整代码如下。

LogRocket 徽标动画

一个动画结束,还有一个!

我为 LogRocket 图标创建了一个SVG,它很大,所以我将它包含在启动器 CodeSandbox 中,您可以在这里查看。

最终的动画将如下所示:

LogRocket 徽标动画完成

正如您从上面看到的,这不仅仅是我们的第一个动画,所以让我们开始吧!

我们首先要关注的是火箭,它从底部开始动画。我们有一个g带有 的元素idrocket这就是我们要用 GreenSock 实现的目标元素。以前,我们会这样做TweenMax,但现在我们将使用 ,TimelineMax因为我们希望每个元素按顺序动画,而不是一次性全部动画。

我们TimelineMax像这样导入:

import { TimelineMax } from "gsap";
Enter fullscreen mode Exit fullscreen mode

我们首先需要创建一个Timeline,我们通过创建该类的实例来实现TimelineMax

const tl = new TimelineMax();
Enter fullscreen mode Exit fullscreen mode

与 类似TweenMax,我们的实例 ( tl) 也有一个fromTo我们将使用的方法:

tl.fromTo("#rocket", 2, { y: 50 }, { y: 0 });
Enter fullscreen mode Exit fullscreen mode

这与我们的第一个动画非常相似,只是这里ref我们不是使用,而是传递 id — — 无论哪种方式都可以。

现在我们的火箭应该像这样从底部升起:

火箭动画

下一部分是draw字母。所有字母都path包裹在g带有 的标签中id letters,这样我们就能轻松找到它们。为了获得绘图效果,我们需要使用几个attributes,分别是stroke-dasharraystroke-dashoffset。这些相当复杂,如果您想了解更多详细信息,我建议您前往

在我们的例子中,我们使用这些属性将路径分解成小段,以便将它们重新组合在一起,从而实现绘制效果。我的经验法则是将两个属性的值设置为相同,这样一旦文本消失,就可以继续使用了。100是我们将采用的值。

因此,在我们的styles.css文件中,我们将在路径上设置这两个属性,如下所示:

svg #letters path {
  stroke-dasharray: 100;
  stroke-dashoffset: 100;
}
Enter fullscreen mode Exit fullscreen mode

附带说明一下,stroke必须存在才能使其path工作(这包括从父级path继承)。stroke

因此,您现在看到的是以下内容:

已删除描边的 LogRocket 字标

这和我们之前的一样,但字母没有那么粗——那是因为我们去掉了stroke,但它仍然有一个fill。下一步是将 设置fill-opacity0

svg #letters path {
  stroke-dasharray: 100;
  stroke-dashoffset: 100;
  fill-opacity: 0;
}
Enter fullscreen mode Exit fullscreen mode

有了这个,我们的信件就消失了,所以现在我们专注于找回它们。

我们需要做的就是将动画strokeDashoffset返回到0。我们将使用我们的tl实例和to方法。

tl.to("#letters path", 3, {
  strokeDashoffset: 0
});
Enter fullscreen mode Exit fullscreen mode

如你所见,我们使用letters选择器,然后选中path该组中的每个字母。这样,我们的字母现在就可以开始绘制了:

带有字母路径的动画 LogRocket 徽标

最后一个难题是为fill-opacityto制作动画1。我们再次使用tl实例和to方法。

tl.to("#letters path", 3, { "fill-opacity": 1 });
Enter fullscreen mode Exit fullscreen mode

就这样!我们的 LogRocket 动画完成了——还不错吧?

LogRocket 徽标动画完成

你可以从这里看到它的威力TimelineMax。通常,要按顺序运行动画,你必须使用延迟,但TimelineMax我们已经处理好了。

完整的 CodeSandbox 可以在下面找到。

结论

好了,各位,就到这里。这绝对更像是对 GreenSock 的介绍,而不是 React Hooks 的介绍,但我希望你们对两者都有所了解。GreenSock 的团队为他们的库投入了大量精力,所以一定要更进一步,用它来创作精彩的动画。


编者注:觉得这篇文章有什么问题?您可以在这里找到正确版本

插件:LogRocket,一个用于 Web 应用的 DVR

 
LogRocket 仪表板免费试用横幅
 
LogRocket是一款前端日志工具,可让您重放问题,就像它们发生在您自己的浏览器中一样。您无需猜测错误发生的原因,也无需要求用户提供屏幕截图和日志转储,LogRocket 允许您重放会话以快速了解问题所在。它可与任何应用程序完美兼容,无论使用哪种框架,并且提供插件来记录来自 Redux、Vuex 和 @ngrx/store 的更多上下文。
 
除了记录 Redux 操作和状态之外,LogRocket 还记录控制台日志、JavaScript 错误、堆栈跟踪、带有标头 + 正文的网络请求/响应、浏览器元数据以及自定义日志。它还会对 DOM 进行插桩,以记录页面上的 HTML 和 CSS,即使是最复杂的单页应用程序,也能重现像素完美的视频。
 
免费试用


使用 React Hooks 和 GreenSock 的动画一文首先出现在LogRocket 博客上。

文章来源:https://dev.to/bnevilleoneill/animations-using-react-hooks-and-greensock-2o80
PREV
Axios 或 fetch():您应该使用哪一个?
NEXT
全面理解 Redis 的指南