以下内容是个整体功能的描述,不会对所有api进行说明讲解,主要是关键性内容描述。

前言

作为一个前端开发,不可避免地需要开发动画。如果自己临时写一个动画,还是比较容易出问题的,今天介绍一个很好用的动画库,功能十分强悍 ———— GSAP。

效果

说再多,也不如直接来效果来的直观。
如果能科学上网可以查看以下官网链接:

  1. GSAP动画:greensock.com/showcase/
  2. GSAP ScrollTrigger(gsap的插件)动画:greensock.com/st-demos/

GSAP

安装 && 基础api

安装

pnpm install gsap (其他方式也行,注意:在vue、react等框架下使用,应在dom渲染后调用)

to:

  1. 代码: gsap.to(目标dom, { x: 300, y: 100, duration: 1, ease: 'back' })
  2. 效果说明:目标dom,translate(300px,100px),持续过程1s,过渡动画:back(后面讲解)
  3. 效果:04e7b486-eeed-49a9-bc9b-07f7c8efb5f6.gif

from:

  1. 代码:gsap.from(目标dom, { x: 300, duration: 1, delay: 1 })
  2. 效果说明:目标dom,初始化translateX(300px),然后回到原本代码的位置,持续过程1s,延长1s执行
  3. 效果:33a7232d-411d-41cb-9243-d580c9be71db.gif

fromTo:

  1. 代码:gsap.fromTo(目标dom, { x: 300, y: 100 }, { x: 100, y: 50 })
  2. 效果说明:目标dom,初始化translate(300px, 100px),去往translateX(100px, 50px),持续过程: 默认时间
  3. 效果:00eb21f5-99df-4a31-b5fa-0c6ecbf6f90e.gif

常用参数说明

例如:gsap.to(to.value, { x: 300, y: 100 }) ,参数是:x、y

参数列表

  1. keyframes:类似css的keyframes,执行多段动画,例如:gsap.to(目标dom, { keyframes: [{x: 100}, {y: 100}] })
  2. esae:缓冲动画函数。img
  3. x、y:移动到x、y的位置,对应api:translate
  4. duration: 动画持续时间,单位: s
  5. delay:动画延迟执行,单位:s
  6. repeat:重复执行动画,单位:次,无限次数则:-1
  7. yoyo:是否原路返回执行,配合repeat使用。例如:yoyo: false,执行:1-2-3-1-2-3-1-2-3;则,yoyo:true,执行效果:1-2-3-3-2-1-1-2-3
  8. repeatDelay: repeat延迟执行,单位:s
  9. 其他:top、left、borderSize、borderRaduis、width、height等css属性

Hooks

  1. onComplete:动画执行完成回调;回调函数的参数:onCompleteParams: any[]
  2. onRepeat:动画重复执行回调;回调函数的参数:onRepeatParams: any[]
  3. onStart:动画重复执行回调;回调函数的参数:onStartParams: any[]

例如:

gsap.to(目标dom, {
        width: 'auto',
        repeat: 3,
        repeatDelay: 0.5,
        yoyo: true,
        esas: 'back',
        onRepeatParams: [1, '2', 3],
        onRepeat() {
          console.log('重复执行的回调')
          console.log('回调的参数:', arguments)
        },
        onComplete() {
          console.log('动画执行完成')
        },
        onStart() {
          console.log('动画从起始位置开始执行,即repeat会重复触发')
        }
      })

关键api:Timeline

先看效果

1.代码:

const t1 = gsap.timeline()
t1.to(目标dom, { x: 300, duration: 0.5 })
  .to(目标dom, { y: 100, duration: 1 })
  .to(目标dom, { x: 0, y: 0, duration: 1 })

代码说明:实例化一个timeline,对一个或者多个目标dom进行时间轴的动画效果。时间轴时间长度为:实例内duration的总长度,根据链式调用的顺序和时间,进行依次调用,上一个dom动画完成再到下一个dom动画(可以是同一个dom,也可以是不同的dom)。

2.效果:3cc9555c-28a6-44a4-8fc4-b4f8ca740b04.gif

Timeline详解

一个复杂的动画由多个补间动画组成的,而timeline的作用就是整体上串联所有的补间动画

多dom例子

// timeline重复两次,每次重复延迟2s
const tl = gsap.timeLine({repeat:2,repeatDelay:2})
    // box1 先向右移动100像素,耗时1秒,接着box2向下平移100像素,耗时1秒
    tl.to('.tl_1',{x: 100, duration: 1})
    tl.to('.tl_2',{y: 100,duration: 1})

20230421-110639.gif

时间轴定义

默认序列

20230421-113338.gif

相对序列

20230421-113435.gif 20230421-113509.gif

绝对序列

20230421-113538.gif

label序列

20230421-113607.gif

常用参数

  1. repeat: 时间轴动画重复次数,类型number
  2. repeatDelay: 重复动画间隔时间(以秒为单位),类型number
  3. yoyo:重复动画交替方式,类型boolean(同上文yoyo)
  4. delay:时间轴开始之前的延迟(以秒为单位),类型number
  5. reversed:时间轴动画是否倒放,类型boolean
  6. onComplete: 时间轴动画完成回调,类型(…args: any[]) => void | null
  7. onRepeat:时间轴动画重复执行回调,类型(…args: any[]) => void | null
  8. onStart: 时间轴动画开始执行回调,类型(…args: any[]) => void | null
  9. onUpdate:时间轴动画运行时回调,类型(…args: any[]) => void | null
  10. autoRemoveChildren:动画完成是否杀死补间动画,好处减少内存占用,类型boolean

常用函数(以下tl是:const t1 = gsap.timeline()

实例方法可能会破坏,原本参数的预期的动画和参数的设定

与上述例子相同,onComplete勾子,添加reverse方法,会发现重复执行参数不生效:

const tl = gsap.timeline({ repeat: 2, repeatDelay: 2 })
    // box1 先向右移动100像素,耗费1秒,接着box2向下平移100像素,耗费1秒
    tl.to('.tl_1', { x: 100, duration: 1 })
    tl.to('.tl_2', {
        y: 100,
        duration: 1,
        onComplete: () => {
          tl.reverse()
        }
    })

20230421-110639.gif

  1. tl.pause(): 暂停动画
  2. tl.reverse(): 反向播放动画
  3. tl.add(): 添加补间动画(对比上面和下面的timeline例子)
  4. tl.addLabel(): 在时间线上添加标签,便于标记重要位置/时间
const tl = gsap.timeLine()
tl.add(gsap.to('.box',{x:100,duration:2}))

// 在.box动画运行2秒后,再等1秒做个记录,也就是firstStep是3秒的标记
tl.addLabel('timeFlag','+=1')

// 这时.box1执行的时间是: .box执行时间 + 标记加上的时间 = 3s开始
tl.add(gsap.to('.box1',{x:100,duration:1}, 'timeFlag'))
  1. tl.seek(): 跳到指定的时间
const tl = gsap.timeLine()
tl.seek(1) // 跳到1秒初
tl.seek('+=1') // 相对时间,当时时间+1
tl.seek('label') // 跳到指定标签处 (应先添加label)
  1. tl.progress(): 进度跳转在0~1之间
  2. tl.kill(): 杀死动画
  3. tl.to
  4. tl.from
  5. ……

GSAP ScrollTrigger

ScrollTrigger是GSAP的插件,它监听页面滚动,然后执行对应的gsap。

简单点理解:ScrollTrigger就是,让页面滚动条等价于timeline的时间轴,滚动页面就是timeline时间轴前进,回滚则是时间轴回退

ScroolTrigger有多种方式运行,以下我们主要以timeline + scrollTrigger作为例子。

示例代码 && 解释

代码

const tl = this.$gsap.timeline({
  scrollTrigger: {
    trigger: 相对dom,
    start: 'top 500px',
    end: 'bottom 500px',
    scrub: 0.1,
    markers: true
  }
})

tl.to(动画dom, { x: 100, opacity: 0 })

代码解释

我们可以看到timeline()里面多了scrollTrigger的参数集,以下对上面代码的参数集进行解释:

  1. trigger:相对dom,选取一个dom,作为参考坐标系。以该dom的位置,和可视屏幕位置,结合下面的start、end属性,决定动画dom什么时候开始动画,什么时候结束动画

  2. start:

    动画dom开始的时机

    1. 参数1:相对dom的位置,例如:top | 50px | 10%;
    2. 参数2: 屏幕的位置,例如:top | 200px | 30%
  3. end:

    动画dom结束的时机

    1. 参数1: 相对dom的位置,例如:top | 50px | 10%;
    2. 参数2: 屏幕的位置,例如:top | 200px | 30%
  4. scrub:缓冲动画的延迟时间,时间越大,延迟越高。例如设置1: 屏幕滚动1s后,开始执行动画。最终动画的位置与scrub无关,与startend有关

  5. markers: 将triggerstartend属性之间的关系,在屏幕表示出来。看不懂打开这个属性,就懂了

image.png

结合上图:当start标线与scroller-start处于相同位置,“动画dom”开始执行动画;当end标线与scroller-end处于相同位置,“动画dom”结束动画

20230421-153544.gif

稍复杂动画

gsap.timeline({
  scrollTrigger: {
    trigger: '#page2',
    start: 'top top',
    end: 'bottom top',
    scrub: 0.1,
    pin: true,
  }
})
const tl2 = gsap.timeline({
  scrollTrigger: {
    trigger: '#page2 .target2',
    start: 'top top',
    end: 'bottom top',
    scrub: 0.1,
    markers: true
  }
})

tl2.fromTo('#page2 .img3', { x: 0 }, { x: 600, rotateZ: 360, borderRadius: "50%" })
tl2.fromTo('#page2 .img4', { x: 800, width: 0, opacity: 0 }, { width: 250, x: 400, y: 200, opacity: 1 })
tl2.fromTo('#page2 .img5', { x: 500, y: 350, width: 0 }, { width: 1000, x: 0, y: 100 })
tl2.to('#page2 .img5', { x: 100, y: 600, width: 300, borderRadius: '50%' })

20230421-161920.gif

demo 链接

github.com/goodrufu/gs…

结语

希望看完这篇文章,可以让你对GSAP有个整体感知,能够知道这是个什么东西,能够做什么。如果,文章能让你快速上手,那是最好不过了。

转自:https://juejin.cn/post/7224402365452910650…