用 Next.js 与 GSAP 打造丝滑动效
用 Next.js 与 GSAP 打造丝滑动效
先给大家分享一个小故事,聊聊我是如何接触到 GSAP 的,以及为什么要在 Next.js 项目里引入它。
一、遇见 GSAP 的小故事
前段时间,我在翻阅各大汽车厂商的官网设计,看到某汽车品牌的首页动效非常出色:
- 首屏的标题缓缓浮现
- 滚动到车型展示区时,3D 视差动画十分流畅
- 底部 CTA 按钮还有细微弹性反馈
当时单纯好奇,没想过是库,就以为这个车厂好,官网都做得这么细,汽车本质差不了,本想自己复现一下,发现越写越麻烦,然后就去翻控制台发现它们用的是一套定制化动画引擎,回头一查,才知道原来业内的头部大厂大都在使用 GSAP (GreenSock Animation Platform),以前工作几乎很少写复杂的动画,基本一些简单的animation就可以,所以这里就记录一下。GSAP 作为 框架无关 的高级动画库,可以无缝支持 CSS、SVG、Canvas、React、Vue、WebGL 等所有可由 JavaScript 操控的对象。
二、在 Next.js 中引入 GSAP
为了在 Next.js 应用中使用 GSAP,你需要先安装核心包以及 React 适配包:
pnpm install gsap @gsap/react
注意,为了减少把NextJS逐渐写成了React,要将注册单独放入一个空间注册
//components/GSAPInitializer.tsx
'use client'
import { useEffect } from 'react'
import { gsapInit } from '@/app/utils/gsapInit'
const GSAPInitializer: React.FC = () => {
useEffect(() => {
gsapInit()
}, [])
return null
}
export default GSAPInitializer
// utils/gsapInit.ts
// 注册插件的纯模块
import { useGSAP } from '@gsap/react'
import gsap from 'gsap'
let hasRegistered = false
export const gsapInit = (): void => {
if (!hasRegistered) {
gsap.registerPlugin(useGSAP)
hasRegistered = true
if (process.env.NODE_ENV === 'development') {
console.log('GSAP plugin registered.')
}
}
}
然后去到根目录,正常引入就好,这样就不会污染layout.tsx 服务端组件,它只是渲染了一个客户端子组件,不会强制自己变成客户端。这样就完美分离了 SSR 和动画初始化逻辑
import type { Metadata } from 'next';
import './styles/index.css';
import type { FC, PropsWithChildren } from 'react';
import GSAPInitializer from './_components/GSAP/GSAPInitializer';
export const metadata: Metadata = {
title: 'nextapp',
description: '我的记录本',
};
const RootLayout: FC<PropsWithChildren> = ({ children }) => {
return (
<html lang="en">
<GSAPInitializer />
<body>{children}</body>
</html>
);
};
export default RootLayout;
以上代码展示了如何用 import { useGSAP } from '@gsap/react' 将动画钩子和 GSAP 结合,方便在 React 环境下使用,并自动处理生命周期。
三、封装「底部向上渐显」文字组件
在实际项目中,我们经常需要将一段段文字从底部向上按行依次淡入。
3.1 组件代码
// gsap: 从下至上渐显动画
'use client';
import { useGSAP } from '@gsap/react';
import gsap from 'gsap';
import { useRef } from 'react';
interface FadeUpProps {
children: React.ReactNode; //内容
duration?: number; //执行时间
delay?: number; //延迟
distance?: number; //距离
stagger?: number; //比例
index?: number; //索引
}
export default function FadeUp({
children,
duration = 1,
delay = 0,
distance = 50,
stagger = 0.3,
index = 1,
}: FadeUpProps) {
const wrapperRef = useRef<HTMLDivElement>(null);
useGSAP(() => {
gsap.fromTo(
wrapperRef.current,
{ y: distance, opacity: 0 },
{
y: 0,
opacity: 1,
duration,
delay: delay || (index * stagger).toFixed(1),
ease: 'power3.out',
},
);
});
return <div ref={wrapperRef}>{children}</div>;
}
3.2 使用示例
import type { FC } from 'react';
import FadeUp from '../_components/GSAP/FadeUp';
const App: FC = () => {
return (
<main>
<FadeUp>欢迎来到cuiji的档案室,这里是cuiji的代码人生和生活的记录</FadeUp>
</main>
);
};
export default App;
四、GSAP 常用 API 总览
以下是 GSAP 在日常使用中最常见的几组 API,皆摘自官方速查表,可快速上手:
参考文献
• GSAP 官方 GitHub 与文档 • React 中更简单的使用 gsap 的方式:useGSAP 钩子介绍 • GSAP Cheat Sheet(基础动画与控制方法) • ScrollTrigger 插件深度示例与总结