04 Three使用Gsap动画库

lxf2023-03-13 10:08:01

GSAP (GreenSock Animation Platform),构建适用于所有主流浏览器的高性能动画。可应用于JavaScript相关的任何东西:动画 CSS、SVG、画布、React、Vue、WebGL、颜色、字符串、运动路径、通用对象......

1. Gsap入门

Gsap官方入门教程: greensock.com/get-started…

1.1 Gsap下载和引用

npm install gsap

04 Three使用Gsap动画库

import gsap from 'gsap'
// 或者 import { gsap } from 'gsap'

04 Three使用Gsap动画库

1.2 Gsap实现一些简单的动画

1-2-1 gsap.to()

gsap.to(选择器,状态对象) 是指从原有状态 变化成参数里的状态对象

// html元素创建动画,将 '.box' 类的元素设置3秒时间水平移动 300px 的动画
gsap.to(".box",{
  duration: 3,
  x: 300
})

04 Three使用Gsap动画库

gsap.to() - 最常见的补间类型。当前元素或者变量的状态,过渡到目标状态的补间动画。

所谓的补间动画,就是2个关键帧(即2种物体的状态)有了,框架自带计算出中间某个时刻的状态,从而填补2个状态间,动画的空白时刻,从而实现完整动画。

gsap.to有2个参数,第一个是目标元素或者变量。

  • 如果传入的是.box之类的css字符串选择器,GSAP 在后台使用document.querySelectorAll()选中页面的匹配的元素。
  • 当第一个目标是对象时,GSAP就会对其属性值进行修改来实现补间动画。

1-2-2 gsap.from()

gsap.from(选择器,状态对象) 是指从参数里的状态对象表现的状态 回归成现有的状态

gsap.from(".circle", { x: -40, fill: 'blue', });

1-2-3 gsap.fromTo()

gsap.fromTo(选择器,状态对象A,状态对象B)是指从状态B,回归到状态A

gsap.fromTo".circle",{ x: -40, fill'blue', }, { x40, fill'green' });

04 Three使用Gsap动画库

1.3 gsap.to()的两个参数

1-3-1 第一个参数——CSS选择器或者Object对象

可以是一个 CSS选择器Element 也可以是一个 Object 对象

const obj = { props: 3 }
gsap.to(obj, {
  props: 100,
  duration: 3,
  onUpdate: function (a, b, c) {
    console.log(obj.props)
  }
})

04 Three使用Gsap动画库

1-3-2 第二个参数——目标状态对象

第二个参数是个对象,接受动画的目标状态,为了区分类型和后续方便理解,它的属性包含三种类型,动画状态运动方式回调函数

1-3-2-1 动画状态的控制属性
参数释义
delay: 2延时播放,单位s
duration: 3动画持续时间,单位s
repeat: 3动画重复播放的次数,-1为一直重复
repeatDelay: 3重复播放间隔时间,单位s
yoyo: false如果true,每隔一个重复,东环将沿相反方向运行
ease: "bounce"控制动画期间的变化率
paused: truetrue 暂停播放动画
stagger: { grid: [7,15], from: "end", axis: "x", ease: "power3.inOut", amount: 1.5 }交错动画

1-3-2-2 运动方式——CSS属性
参数相对应的CSS
x: 100transform: translateX(100px)
y: 100transform: translateY(100px)
rotation: 360transform: rotate(360deg)
rotationX: 360transform: rotateX(360deg)
rotationY: 360transform: rotateY(360deg)
skewX: 45transform: skewX(45deg)
skewY: 45transform: skewY(45deg)
scale: 2transform: scale(2, 2)
scaleX: 2transform: scaleX(2)
scaleY: 2transform: scaleY(2)
xPercent: -50transform: translateX(-50%)
yPercent: -50transform: translateY(-50%)
width: 100width: 100px
height: '10vh'height: 10vh
1-3-2-3 动画的回调函数
事件释义
onStart动画开始播放时触发
onComplete所有动画播放完毕后调用的函数(如果有repeat,则等所有的循环结束后执行)
onRepeat如果有repeat一组动画播放完的回调函数
onUpdate动画运动过程中的回调函数
onReverseComplete触发reverse后回到起点时触发
1-3-2-4 ease属性——动画的速度变化

在引擎内部,“ease”是一种数学计算,用于控制补间期间的变化率。框架会为您做所有的数学计算!只需选择最适合的动画的效果即可。

对于大多数效果,分为三种类型in、out、inOut。这些控制了动画过程中的动量。

像这样的 设置ease:"power1.out" 是 UI 过渡的最佳选择;它们开始速度很快,在接近结束时变慢。

ease: "power1.in"
// start slow and end faster, like a heavy object falling

ease: "power1.out"
// start fast and end slower, like a rolling ball slowly coming to a stop

ease: "power1.inOut"
// start slow and end slow, like a car accelerating and decelerating

理解ease的最好方法是ease配置的可视化工具!

地址:GreenSock | Docs | Eases

04 Three使用Gsap动画库

1-3-2-5 Staggers 动画添加交错效果

在每个动画的开始之间添加一些交错效果:

04 Three使用Gsap动画库

stagger设置0.2,即为将.box选中的多个元素设置为每隔0.2秒开始运动1个元素的效果。

<!DOCTYPE html>
<html lang="en">
  <head>
    <script src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/16327/gsap-latest-beta.min.js"></script>
    <link
      rel="stylesheet"
      href="https://codepen.io/GreenSock/pen/gOWxmWG.css"
    />
    <style>
      @import url('https://fonts.googleapis.com/css2?family=Signika+Negative:wght@400;600&display=swap');

      body {
        display: flex;
        align-items: center;
        justify-content: space-around;
        min-height: 100vh;
        font-family: 'Signika Negative', sans-serif;
      }

      h3 {
        position: fixed;
        top: 0;
        width: 100%;
        text-align: center;
      }

      .box {
        cursor: pointer;
      }
    </style>
  </head>
  <body>
    <div class="box green"></div>
    <div class="box purple"></div>
    <div class="box orange"></div>
    <div class="box purple"></div>
    <div class="box green"></div>

    <h3>Click a box to transition out</h3>
    <script>
      gsap.from('.box', {
        duration: 2,
        scale: 0.5,
        opacity: 0,
        delay: 0.5,
        stagger: 0.2,
        ease: 'elastic',
        force3D: true
      })

      document.querySelectorAll('.box').forEach(function (box) {
        box.addEventListener('click', function () {
          gsap.to('.box', {
            duration: 0.5,
            opacity: 0,
            y: -100,
            stagger: 0.1,
            ease: 'back.in'
          })
        })
      })
    </script>
  </body>
</html>
1-3-2-6 时间线-Timelines

时间线用于创建一组按照顺序播放的动画。当您将补间添加到时间线时,默认情况下,它们会按照添加的顺序一个接一个地播放。

// 创建时间线动画
let tl = gsap.timeline()

// 现在用时间线tl代替上边的gsap来设置动画即可。
tl.to(".green", { x: 600, duration: 2 });
tl.to(".purple", { x: 600, duration: 1 });
tl.to(".orange", { x: 600, duration: 1 }) 

04 Three使用Gsap动画库

1.4 gsap.to()的返回值——控制动画的进行

gasp.to 等执行后会返回一个 tween 实例。它有一些 api 可以控制动画的进行,比如:

const tween = gsap.to('body', {
  x: 300,
  duration: 3
})
console.log(tween.duration()) // 相当于Getter 获取当前动画总共需要执行3秒
tween.duration(1)

console.log('返回值tween实例', tween)
console.log('原型', tween.__proto__.__proto__)

上述代码,原先动画的执行时间是 duration: 3 需要3秒才能完成动画的播放

但通过设置了tween.duration(1)后,动画总时长只执行了1秒

04 Three使用Gsap动画库

api释义
time从哪个时刻开始执行动画,单位是秒
progress从哪个进度开始,参数是 0 ~ 1
duration更改整体动画时间,参数是期望的动画的总时间
delay延时几秒后执行动画,参数是秒
timeScale动画播放速度,数值越大,播放速度越快修改后的播放时间 = 原播放总时长 / timeScale

1.4.1 控制动画播放

通过返回的实例控制播放

const tween = gsap.to('.green', {
  duration: 4,
  x: 750,
  rotation: 360
})
setTimeout(() => {
  tween.pause()
}, 2000)

上述动画原本会持续4秒,2秒过后,触发了 tween.pause() 动画暂停

api释义
play播放
pause暂停
resume继续播放,只能继pause之后播放
reverse回退到起始点
restart从头开始播放
kill直接暂停并销毁实例,后续无法重新播放

04 Three使用Gsap动画库

2 Threejs场景中使用Gsap动画

2.1 设置立方体旋转

gsap.to(
  cube.rotation,
  {
    x: 2 * Math.PI,
    duration: 5,
    repeat: -1,
    ease: "power1.inOut"
  }
);

04 Three使用Gsap动画库

2.2 设置立方体来回往返运动

// 设置动画
var animate1 = gsap.to(cube.position, {
  x: 3,
  duration: 3,
  ease: 'power1.inOut',
  //   设置重复的次数,无限次循环-1
  repeat: -1,
  //   往返运动
  yoyo: true,
  //   delay,延迟2秒运动
  delay: 2,
  // 当动画完成时,执行回调函数
  onComplete: () => {
    console.log('动画完成')
  },
  onRepeat: () => {
    console.log('动画重复一次')
  },
  //当动画开始时,执行回调函数
  onStart: () => {
    console.log('动画开始')
  }
})

04 Three使用Gsap动画库

2.3 控制立方体动画暂停和恢复动画

双击画面,控制立方体动画暂停和恢复动画。

  • 前面创建的animate1这个动画实例,有isActive方法,可以用来获取当前动画是暂停还是播放状态,
  • 播放状态时isActive方法返回为true,暂停时为false,根据这个状态来调用pause方法来暂停动画和恢复动画。
window.addEventListener("dblclick", () => {
  //   console.log(animate1);
  if (animate1.isActive()) {
    //   暂停
    animate1.pause();
  } else {
    //   恢复
    animate1.resume();
  }
}); 

2.4 暂停单个动画——Gsap效果实例

04 Three使用Gsap动画库

import * as THREE from 'three'
// 导入轨道控制器
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'
import gsap from 'gsap'
// console.log(gsap)

// 目标:Three使用Gsap动画

// 1、创建场景
const scene = new THREE.Scene()

// 2、创建相机
const camera = new THREE.PerspectiveCamera(
  75,
  window.innerWidth / window.innerHeight,
  0.1,
  1000
)

// 设置相机位置
camera.position.set(0, 0, 10)
scene.add(camera)

// 添加物体
// 创建几何体
const cubeGeometry = new THREE.BoxGeometry(1, 1, 1)
const cubeMaterial = new THREE.MeshBasicMaterial({ color: 0xffff00 })
// 根据几何体和材质创建物体
const cube = new THREE.Mesh(cubeGeometry, cubeMaterial)
// 将几何体添加到场景中
scene.add(cube)
// console.log(cube)

// 初始化渲染器
const renderer = new THREE.WebGLRenderer()
// 设置渲染的尺寸大小
renderer.setSize(window.innerWidth, window.innerHeight)
// console.log(renderer);
// 将webgl渲染的canvas内容添加到body
document.body.appendChild(renderer.domElement)

// 添加坐标轴辅助器
const axesHelper = new THREE.AxesHelper(3)
scene.add(axesHelper)

// 创建轨道控制器
const controls = new OrbitControls(camera, renderer.domElement)
var animate1 = gsap.to(cube.position, {
  x: 3,
  duration: 3,
  ease: 'power1.inOut',
  //   设置重复的次数,无限次循环-1
  repeat: -1,
  //   往返运动
  yoyo: true,
  //   delay,延迟2秒运动
  delay: 2,
  // 当动画完成时,执行回调函数
  onComplete: () => {
    console.log('动画完成')
  },
  onRepeat: () => {
    console.log('动画重复一次')
  },
  //当动画开始时,执行回调函数
  onStart: () => {
    console.log('动画开始')
  }
})
gsap.to(cube.rotation, {
  x: 2 * Math.PI,
  duration: 3,
  repeat: -1,
  ease: 'power1.inOut'
})
window.addEventListener('dblclick', () => {
  //   console.log(animate1);
  if (animate1.isActive()) {
    //   暂停平移动画animate1
    //  旋转动画不受影响
    animate1.pause()
  } else {
    //   恢复动画animate1
    animate1.resume()
  }
})
function render() {
  renderer.render(scene, camera)
  requestAnimationFrame(render)
}

render()