GSAP 教程 - 高性能 JavaScript 动画库

一、项目概述

GSAP (GreenSock Animation Platform) 是一个功能强大的高性能 JavaScript 动画库,专为创建流畅、复杂的动画效果而设计。它提供了丰富的工具和 API,使开发者能够轻松创建各种动画效果,从简单的淡入淡出到复杂的时间线动画。

1.1 核心概念

  • Tween:基本动画单元,用于定义元素从一个状态到另一个状态的过渡
  • Timeline:时间线,用于组织和控制多个 Tween 的执行顺序和时间关系
  • Easing:缓动函数,控制动画的速度变化
  • Plugin:插件系统,扩展 GSAP 的功能

1.2 核心特点

  • 高性能:经过高度优化,动画流畅度高
  • 功能丰富:提供了全面的动画工具和 API
  • 灵活性:支持各种动画场景和需求
  • 跨浏览器兼容:在所有现代浏览器中表现一致
  • 插件系统:通过插件扩展功能

二、安装与设置

2.1 安装方式

通过 npm 安装:

npm install gsap

通过 CDN 引入:

<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.5/gsap.min.js"></script>

2.2 基本引入

在 ES6 模块中:

import gsap from 'gsap';
// 引入插件
import { ScrollTrigger } from 'gsap/ScrollTrigger';
import { Draggable } from 'gsap/Draggable';

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

在浏览器中:

<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.5/gsap.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.5/ScrollTrigger.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.5/Draggable.min.js"></script>

三、基础用法

3.1 创建基本 Tween 动画

简单的属性动画:

// 基本的淡入效果
gsap.to('.element', {
  opacity: 1,
  duration: 1,
  ease: 'power2.out'
});

// 移动元素
gsap.to('.element', {
  x: 100,
  y: 50,
  duration: 1.5,
  ease: 'back.out(1.7)'
});

// 缩放元素
gsap.to('.element', {
  scale: 1.2,
  duration: 0.8,
  ease: 'elastic.out(1, 0.5)'
});

从某个状态开始动画:

// 从指定状态开始动画
gsap.from('.element', {
  opacity: 0,
  y: -50,
  duration: 1,
  ease: 'power2.out'
});

// 从当前状态动画到指定状态,再回到当前状态
gsap.fromTo('.element', 
  { opacity: 0, scale: 0.8 }, // 起始状态
  { opacity: 1, scale: 1, duration: 1, ease: 'back.out' } // 结束状态
);

3.2 使用 Timeline 组织动画

创建简单时间线:

// 创建时间线
const tl = gsap.timeline({
  repeat: 2, // 重复次数
  yoyo: true, // 往返动画
  ease: 'power2.inOut'
});

// 添加动画到时间线
tl.to('.element1', { x: 100, duration: 1 })
  .to('.element2', { y: 50, duration: 0.8 }, '-=0.5') // 与前一个动画重叠 0.5 秒
  .to('.element3', { scale: 1.2, duration: 1 }, '+=0.3'); // 在前一个动画结束后延迟 0.3 秒开始

标签和时间控制:

const tl = gsap.timeline();

// 添加标签
tl.add('start')
  .to('.element1', { x: 100, duration: 1 })
  .add('midpoint')
  .to('.element2', { y: 50, duration: 0.8 })
  .add('end');

// 使用标签控制动画
// 跳转到指定标签
tl.seek('midpoint');

// 从指定标签开始播放
tl.play('start');

四、高级特性

4.1 ScrollTrigger 插件

基本滚动触发动画:

// 当元素进入视口时触发动画
gsap.registerPlugin(ScrollTrigger);

gsap.from('.section', {
  scrollTrigger: {
    trigger: '.section',
    start: 'top 80%', // 当元素顶部到达视口80%位置时开始
    end: 'bottom 20%', // 当元素底部到达视口20%位置时结束
    toggleActions: 'play none none none' // 滚动时的行为:进入、离开、反向进入、反向离开
  },
  opacity: 0,
  y: 50,
  duration: 1,
  ease: 'power2.out'
});

滚动进度动画:

// 基于滚动进度的动画
gsap.registerPlugin(ScrollTrigger);

const tl = gsap.timeline({
  scrollTrigger: {
    trigger: '.scroll-section',
    start: 'top top',
    end: 'bottom bottom',
    scrub: true // 滚动时 scrub 动画
  }
});

tl.to('.element', { x: 300, duration: 1 })
  .to('.element', { rotation: 360, duration: 1 })
  .to('.element', { scale: 1.5, duration: 1 });

4.2 Draggable 插件

基本拖拽功能:

// 基本拖拽
gsap.registerPlugin(Draggable);

Draggable.create('.draggable', {
  type: 'x,y', // 拖拽方向
  bounds: '.container', // 拖拽边界
  inertia: true, // 惯性
  onDragEnd: function() {
    console.log('拖拽结束');
  }
});

拖拽排序:

// 拖拽排序
gsap.registerPlugin(Draggable);

Draggable.create('.item', {
  type: 'x,y',
  bounds: '.container',
  dragResistance: 0.1,
  onDragEnd: function() {
    // 排序逻辑
    sortItems();
  }
});

function sortItems() {
  // 实现排序逻辑
}

4.3 自定义缓动函数

使用内置缓动:

// 内置缓动函数
gsap.to('.element', {
  x: 100,
  duration: 1,
  ease: 'power1.inOut' // 内置缓动
});

// 弹性缓动
gsap.to('.element', {
  x: 100,
  duration: 1,
  ease: 'elastic.out(1, 0.5)' // 弹性参数
});

// 反弹缓动
gsap.to('.element', {
  x: 100,
  duration: 1,
  ease: 'back.out(1.7)' // 反弹强度
});

创建自定义缓动:

// 创建自定义缓动
const customEase = gsap.parseEase('0.25, 0.1, 0.25, 1');

gsap.to('.element', {
  x: 100,
  duration: 1,
  ease: customEase
});

五、实际应用场景

5.1 页面滚动动画

视差滚动效果:

gsap.registerPlugin(ScrollTrigger);

// 视差背景
gsap.to('.parallax-bg', {
  scrollTrigger: {
    trigger: '.section',
    scrub: true
  },
  y: (i, target) => {
    return -(ScrollTrigger.maxScroll(window) * 0.5);
  },
  ease: 'none'
});

// 元素视差效果
gsap.to('.parallax-element', {
  scrollTrigger: {
    trigger: '.section',
    scrub: true
  },
  y: 100,
  ease: 'none'
});

滚动触发的序列动画:

gsap.registerPlugin(ScrollTrigger);

const tl = gsap.timeline({
  scrollTrigger: {
    trigger: '.feature-section',
    start: 'top 80%',
    toggleActions: 'play none none none'
  }
});

tl.from('.feature-title', { opacity: 0, y: 30, duration: 0.8 })
  .from('.feature-item', { 
    opacity: 0, 
    y: 20, 
    duration: 0.6, 
    stagger: 0.2 //  stagger 动画
  }, '-=0.3');

5.2 交互式动画

鼠标跟随效果:

// 鼠标跟随效果
window.addEventListener('mousemove', (e) => {
  gsap.to('.cursor', {
    x: e.clientX,
    y: e.clientY,
    duration: 0.1,
    ease: 'power2.out'
  });
});

// 鼠标悬停效果
document.querySelectorAll('.card').forEach(card => {
  card.addEventListener('mouseenter', () => {
    gsap.to(card, {
      scale: 1.05,
      boxShadow: '0 10px 30px rgba(0,0,0,0.1)',
      duration: 0.3,
      ease: 'back.out'
    });
  });
  
  card.addEventListener('mouseleave', () => {
    gsap.to(card, {
      scale: 1,
      boxShadow: '0 2px 10px rgba(0,0,0,0.05)',
      duration: 0.3,
      ease: 'power2.out'
    });
  });
});

按钮点击动画:

// 按钮点击波纹效果
document.querySelectorAll('.btn').forEach(btn => {
  btn.addEventListener('click', (e) => {
    const rect = btn.getBoundingClientRect();
    const size = Math.max(rect.width, rect.height);
    const x = e.clientX - rect.left - size / 2;
    const y = e.clientY - rect.top - size / 2;
    
    // 创建波纹元素
    const ripple = document.createElement('span');
    ripple.classList.add('ripple');
    ripple.style.width = ripple.style.height = size + 'px';
    ripple.style.left = x + 'px';
    ripple.style.top = y + 'px';
    btn.appendChild(ripple);
    
    // 动画
    gsap.to(ripple, {
      scale: 2,
      opacity: 0,
      duration: 0.6,
      ease: 'power2.out',
      onComplete: () => {
        ripple.remove();
      }
    });
  });
});

5.3 数据可视化动画

数字计数动画:

// 数字计数动画
function animateCounter(element, start, end, duration) {
  gsap.to({}, {
    duration: duration,
    start: start,
    end: end,
    ease: 'power2.out',
    onUpdate: function() {
      const value = Math.floor(this.targets()[0].start);
      element.textContent = value.toLocaleString();
    },
    onComplete: function() {
      element.textContent = end.toLocaleString();
    }
  });
}

// 使用示例
animateCounter(document.querySelector('.counter'), 0, 1000, 2);

进度条动画:

// 进度条动画
function animateProgress(element, progress, duration) {
  gsap.to(element, {
    width: progress + '%',
    duration: duration,
    ease: 'power2.out'
  });
}

// 使用示例
animateProgress(document.querySelector('.progress-bar'), 75, 1.5);

六、性能优化建议

6.1 动画性能最佳实践

  1. 使用 transform 和 opacity:这些属性不会触发重排,性能更好
  2. 避免频繁 DOM 操作:使用 GSAP 的批量更新功能
  3. 合理使用 will-change:对于频繁动画的元素
  4. 使用 CSS 变量:结合 GSAP 动画 CSS 变量
  5. 优化时间线:合理组织动画顺序,避免重叠过多

6.2 代码优化示例

使用 CSS 变量:

// 定义 CSS 变量
:root {
  --x: 0;
  --y: 0;
  --opacity: 1;
}

.element {
  transform: translate(var(--x), var(--y));
  opacity: var(--opacity);
}

// 动画 CSS 变量
gsap.to(':root', {
  '--x': '100px',
  '--y': '50px',
  '--opacity': 0.5,
  duration: 1
});

使用 will-change:

.animated-element {
  will-change: transform, opacity;
}

批量动画:

// 批量创建动画
const elements = document.querySelectorAll('.items');

gsap.to(elements, {
  x: 100,
  duration: 1,
  stagger: 0.1 // 错开动画
});

七、常见问题与解决方案

7.1 动画不流畅

问题:动画在某些设备上不流畅

解决方案

  • 使用 transform 和 opacity 属性
  • 避免在动画过程中修改布局属性
  • 使用 will-change 提示浏览器
  • 减少同时运行的动画数量

7.2 滚动触发动画不工作

问题:ScrollTrigger 插件的动画不触发

解决方案

  • 确保正确注册了 ScrollTrigger 插件
  • 检查 trigger 元素是否存在
  • 调整 start 和 end 配置
  • 确保滚动容器正确设置

7.3 动画冲突

问题:多个动画同时作用于同一元素导致冲突

解决方案

  • 使用时间线统一管理动画
  • 确保动画的时间不重叠
  • 使用 GSAP 的 kill() 方法停止不需要的动画
  • 考虑使用不同的元素进行动画

八、GSAP 与其他动画库的比较

8.1 GSAP vs CSS 动画

特性 GSAP CSS 动画
性能 极高,经过优化 好,但复杂动画性能下降
功能丰富度 非常丰富,支持复杂动画 基础,复杂动画需要更多代码
浏览器兼容性 优秀,支持所有现代浏览器 良好,但旧浏览器支持有限
控制能力 精确控制,支持暂停、恢复、跳转 基本控制,有限的交互能力
学习曲线 中等,需要学习 API 低,使用 CSS 语法

8.2 GSAP vs Framer Motion

特性 GSAP Framer Motion
性能 极高,专为性能优化 良好,针对 React 优化
适用范围 通用,支持所有前端框架 主要针对 React
功能丰富度 非常丰富,包括 ScrollTrigger、Draggable 等 丰富,专注于 React 动画
集成难度 低,可与任何框架集成 低,专为 React 设计
社区支持 活跃,有大量资源 活跃,React 生态系统集成好

8.3 GSAP vs React Spring

特性 GSAP React Spring
性能 极高,通用动画优化 良好,基于物理模型
动画模型 时间线和 tween 为主 基于物理模型
适用范围 通用,支持所有前端框架 主要针对 React
功能丰富度 非常丰富,工具齐全 中等,专注于物理动画
学习曲线 中等,概念清晰 中等,物理概念需要理解

九、参考资源

9.1 官方资源

9.2 学习资源

9.3 工具与插件

十、总结

GSAP 是一个功能强大、性能优异的 JavaScript 动画库,为前端开发者提供了创建各种复杂动画效果的工具。它的核心优势在于:

  1. 高性能:经过高度优化,动画流畅度高
  2. 功能丰富:提供了全面的动画工具和 API
  3. 灵活性:支持各种动画场景和需求
  4. 跨浏览器兼容:在所有现代浏览器中表现一致
  5. 插件系统:通过插件扩展功能

无论是创建简单的 UI 交互效果,还是复杂的页面滚动动画,GSAP 都能轻松应对。它的 Timeline 系统让动画序列的管理变得简单直观,而各种插件(如 ScrollTrigger 和 Draggable)则进一步扩展了其能力范围。

通过本教程的学习,你应该已经掌握了 GSAP 的基本使用方法和高级特性,可以开始在项目中应用它来创建出色的动画效果了。随着实践经验的积累,你会发现 GSAP 能够帮助你实现几乎任何你能想象到的动画效果,为你的网站和应用增添生动的视觉体验。

« 上一篇 Framer Motion 教程 - React 的生产级动画库 下一篇 » React Spring 教程 - 基于物理的 React 动画库