# GSAP 动画实现示例 ## 核心动画配置 ### 1. GSAP 初始化设置 ```typescript // src/utils/gsapConfig.ts import { gsap } from 'gsap'; import { ScrollTrigger } from 'gsap/ScrollTrigger'; import { ScrollToPlugin } from 'gsap/ScrollToPlugin'; // 注册插件 gsap.registerPlugin(ScrollTrigger, ScrollToPlugin); // 全局配置 gsap.config({ nullTargetWarn: false, force3D: true }); // 默认缓动函数 gsap.defaults({ ease: "power2.inOut", duration: 0.8 }); ``` ### 2. 时间轴导航动画 ```typescript // src/components/TimelineNav.tsx import React, { useEffect, useRef } from 'react'; import { gsap } from 'gsap'; import { ScrollTrigger } from 'gsap/ScrollTrigger'; interface TimelineItem { id: string; title: string; date: string; description: string; } const TimelineNav: React.FC<{ items: TimelineItem[] }> = ({ items }) => { const timelineRef = useRef(null); const progressRef = useRef(null); useEffect(() => { const ctx = gsap.context(() => { // 进度条动画 gsap.to(progressRef.current, { height: '100%', ease: 'none', scrollTrigger: { trigger: document.body, start: 'top top', end: 'bottom bottom', scrub: 1, onUpdate: (self) => { // 更新当前激活的时间节点 const progress = self.progress; const activeIndex = Math.floor(progress * items.length); updateActiveNode(activeIndex); } } }); // 时间节点入场动画 gsap.from('.timeline-node', { scale: 0, opacity: 0, duration: 0.5, stagger: 0.1, ease: 'back.out(1.7)' }); }, timelineRef); return () => ctx.revert(); }, [items]); const scrollToSection = (id: string) => { gsap.to(window, { duration: 1.2, scrollTo: { y: `#${id}`, offsetY: 100 }, ease: "power3.inOut" }); }; return ( ); }; ``` ### 3. 内容区块滚动动画 ```typescript // src/components/ContentSection.tsx import React, { useEffect, useRef } from 'react'; import { gsap } from 'gsap'; import { ScrollTrigger } from 'gsap/ScrollTrigger'; const ContentSection: React.FC<{ data: any; index: number }> = ({ data, index }) => { const sectionRef = useRef(null); const contentRef = useRef(null); useEffect(() => { const ctx = gsap.context(() => { // 创建时间线 const tl = gsap.timeline({ scrollTrigger: { trigger: sectionRef.current, start: 'top 80%', end: 'bottom 20%', toggleActions: 'play none none reverse', markers: false // 开发时可设为true查看触发点 } }); // 标题动画 tl.from('.section-title', { y: 100, opacity: 0, duration: 1, ease: 'power3.out' }); // 内容交错动画 tl.from('.content-item', { x: index % 2 === 0 ? -150 : 150, opacity: 0, duration: 0.8, stagger: 0.2, ease: 'power2.out' }, '-=0.5'); // 图片视差效果 gsap.to('.parallax-image', { yPercent: -20, ease: 'none', scrollTrigger: { trigger: sectionRef.current, start: 'top bottom', end: 'bottom top', scrub: 1 } }); }, sectionRef); return () => ctx.revert(); }, [index]); return (

{data.title}

{data.items.map((item: any, i: number) => (
{item.title}

{item.title}

{item.description}

))}
); }; ``` ### 4. 图片查看器动画 ```typescript // src/components/ImageViewer.tsx import React, { useState, useRef, useEffect } from 'react'; import { gsap } from 'gsap'; const ImageViewer: React.FC<{ images: string[] }> = ({ images }) => { const [selectedImage, setSelectedImage] = useState(null); const modalRef = useRef(null); const imageRef = useRef(null); useEffect(() => { if (selectedImage && modalRef.current && imageRef.current) { // 模态框背景动画 gsap.fromTo(modalRef.current, { opacity: 0 }, { opacity: 1, duration: 0.3 } ); // 图片缩放入场 gsap.fromTo(imageRef.current, { scale: 0.5, opacity: 0, rotation: -10 }, { scale: 1, opacity: 1, rotation: 0, duration: 0.5, ease: "back.out(1.7)" } ); } }, [selectedImage]); const closeViewer = () => { // 退出动画 const tl = gsap.timeline({ onComplete: () => setSelectedImage(null) }); tl.to(imageRef.current, { scale: 0.8, opacity: 0, duration: 0.3, ease: "power2.in" }); tl.to(modalRef.current, { opacity: 0, duration: 0.2 }, '-=0.2'); }; const handleZoom = (scale: number) => { gsap.to(imageRef.current, { scale: scale, duration: 0.4, ease: "power2.inOut" }); }; return ( <> {/* 图片网格 */}
{images.map((src, index) => (
setSelectedImage(src)} onMouseEnter={(e) => { gsap.to(e.currentTarget.querySelector('img'), { scale: 1.1, duration: 0.3 }); }} onMouseLeave={(e) => { gsap.to(e.currentTarget.querySelector('img'), { scale: 1, duration: 0.3 }); }} >
))}
{/* 查看器模态框 */} {selectedImage && (
{ e.stopPropagation(); handleZoom(2); }} /> {/* 控制按钮 */}
)} ); }; ``` ### 5. 页面加载动画 ```typescript // src/components/LoadingAnimation.tsx import React, { useEffect, useRef } from 'react'; import { gsap } from 'gsap'; const LoadingAnimation: React.FC<{ onComplete: () => void }> = ({ onComplete }) => { const loaderRef = useRef(null); useEffect(() => { const tl = gsap.timeline({ onComplete: onComplete }); // Logo动画 tl.from('.logo-text', { y: 100, opacity: 0, duration: 1, ease: 'power3.out' }); // 进度条动画 tl.to('.progress-bar', { width: '100%', duration: 2, ease: 'power2.inOut' }); // 退出动画 tl.to(loaderRef.current, { yPercent: -100, duration: 0.8, ease: 'power3.inOut' }); }, [onComplete]); return (

订单班展示

); }; ``` ## 性能优化技巧 ### 1. ScrollTrigger 优化 ```typescript // 批量创建 ScrollTrigger ScrollTrigger.batch('.animate-item', { onEnter: (batch) => gsap.to(batch, { opacity: 1, y: 0, stagger: 0.15, overwrite: true }), onLeave: (batch) => gsap.to(batch, { opacity: 0, y: 100, stagger: 0.15, overwrite: true }), onEnterBack: (batch) => gsap.to(batch, { opacity: 1, y: 0, stagger: 0.15, overwrite: true }), onLeaveBack: (batch) => gsap.to(batch, { opacity: 0, y: -100, stagger: 0.15, overwrite: true }) }); // 刷新 ScrollTrigger ScrollTrigger.refresh(); ``` ### 2. 清理和内存管理 ```typescript useEffect(() => { // 创建上下文 const ctx = gsap.context(() => { // 所有GSAP动画代码 }, containerRef); // 清理函数 return () => { ctx.revert(); // 清理所有动画 ScrollTrigger.getAll().forEach(trigger => trigger.kill()); }; }, []); ``` ### 3. 响应式处理 ```typescript useEffect(() => { // 创建媒体查询 const mm = gsap.matchMedia(); mm.add("(min-width: 768px)", () => { // 桌面端动画 gsap.to('.desktop-element', { x: 100, duration: 1 }); }); mm.add("(max-width: 767px)", () => { // 移动端动画 gsap.to('.mobile-element', { y: 50, duration: 0.8 }); }); return () => mm.revert(); }, []); ``` ## 常用缓动函数 ```typescript // GSAP 内置缓动函数 const easings = { smooth: "power2.inOut", // 平滑过渡 snappy: "power3.out", // 快速停止 bounce: "bounce.out", // 弹跳效果 elastic: "elastic.out(1, 0.3)", // 弹性效果 back: "back.out(1.7)", // 回弹效果 expo: "expo.out", // 指数缓动 slow: "power4.inOut", // 缓慢过渡 custom: "cubic-bezier(0.68, -0.55, 0.265, 1.55)" // 自定义贝塞尔曲线 }; ``` ## 注意事项 1. **性能考虑** - 使用 `will-change` CSS属性优化动画元素 - 避免同时动画过多元素 - 使用 `force3D: true` 启用硬件加速 2. **移动端优化** - 减少移动端的动画复杂度 - 使用 `gsap.matchMedia()` 做响应式处理 - 考虑使用 `reduced-motion` 媒体查询 3. **调试技巧** - 使用 `markers: true` 查看 ScrollTrigger 触发点 - 使用 GSDevTools 插件进行动画调试 - 控制台使用 `gsap.globalTimeline.timeScale(0.5)` 减慢所有动画 4. **最佳实践** - 始终使用 `gsap.context()` 管理动画 - 组件卸载时清理所有动画和 ScrollTrigger - 使用 `overwrite: true` 避免动画冲突