如果你发现你写了好几个Tween动画,来让某个元素变化到一个目标状态,那么可能你是需要使用关键帧(KeyFrames)的方式来做了。关键帧动画能让元素的属性变化分段进行,同时又能保持代码的清爽整洁。

比如下面这个代码,同样一个变化效果,我们先用timeline的方式来实现,然后再用关键帧的方式来实现,显然关键帧的方式看起来简洁多了:

Understanding GSAP Keyframes

// timeline
let tl = gsap.timeline();
tl.to(".box", {
    x: 100
  })
  .to(".box", {
    y: 100
  })
  .to(".box", {
    x: 0
  })
  .to(".box", {
    y: 0
  });

// 用数组的方式
gsap.to(".box", {
  keyframes: {
    x: [0, 100, 100, 0, 0],
    y: [0, 0, 100, 100, 0],
    ease: "power1.inOut"
  },
  duration: 2
});

我们可以把关键帧动画了解成用Tween动画包裹的一种类似时间线的动画模式。还有一些其他的方法能够实现关键帧动画。如果你喜欢视频教程,可以看下面这个视频:

关键帧选项

Object keyframes - v3.0

通过对象的数据实现 - GSAP3.0版本开始支持

这个写法可以让你给keyframes属性传入一个数组,这个数组里面是多个对象,这些对象的效果是依次执行,这有点像是一系列Tween的动画,类似timeline的效果。你可以通过给某个动画设置delay来让动画之间产生一定的间隔(delay是正值)或者重叠(delay是负值)。

关键帧动画的默认动画曲线是线性的,也就是线性匀速的动画,你可以在每个动画中都重新定义ease的设置,你也可以给整个关键帧动画添加一个统一的的动画曲线设置。

gsap.to(".elem", {
 keyframes: [ // 注意这里是数组
  {x: 100, duration: 1, ease: 'sine.out'}, // 定义这个分段动画自己的ease曲线
  {y: 200, duration: 1, delay: 0.5}, // 产生和前个分段动画0.5秒的间隔
  {rotation: 360, duration: 2, delay: -0.25} // 和前一个分段动画产生0.25秒的重叠
 ],
 ease: 'expo.inOut' // 设置整个关键帧动画的曲线
});

Percentage keyframes - v3.9

百分比的方式 - GSAP3.9版本开始支持

这个写法和CSS中的关键帧动画的写法是很类似的。 不需要给每一段动画单独设置时长和延时,只要给整体设置一个时长,然后确定每个分段动画的时间比例。

这样的写法,默认的ease曲线是power1.inout,这个曲线看起来的整个变化效果是不错的,但是如果你想要指定每个分段变化的动画曲线,你可以通过每个分段动画内部的ease曲线,或者也可以通过easeEach属性来设置。

gsap.to(".elem", {
 keyframes: {  // 注意这里是对象
  "0%":   { x: 100, y: 100},
  "75%":  { x: 0, y: 0, ease: 'sine.out'}, // 指定这个分段的动画曲线
  "100%": { x: 50, y: 50 },
   easeEach: 'expo.inOut' // 每个分段的动画曲线
 },
 ease: 'none' // 整个关键帧动画的动画曲线
 duration: 2,
})

Simple Array-based keyframes - v3.9

数组的方式关键帧数据写法 - GSAP3.9版本开始支持

通过数组的方式,各个分段自动平均分总时长。

这样的写法,默认的ease曲线是power1.inout,或者也可以通过easeEach属性来设置所有分段的ease曲线。

gsap.to(".elem", {
 keyframes: { // 注意这里是对象
  x: [100, 0, 50], // 数组分段,也就是两段动画,100-0,,0-50
  y: [100, 0, 50]
  easeEach: 'sine.inOut' // 每个分段都设置成这个动画曲线
  ease: 'expo.out' // 关键帧整体的动画曲线设置
 },
 duration: 2, // 总时长2秒,这里有两段,平均分就是每段的时长是1秒
})

关键帧的动画曲线

动画过渡曲线对于动画效果来说是必需品,在使用关键帧的时候,我们也可以非常方便的对关键帧动画进行动画曲线的设置。

百分比的关键帧动画(Percentage keyframes)和简单的关键帧动画(Simple Array-based keyframes),都可以设置easeEach属性,来让每一个分段有自己的动画曲线效果,注意这里是所有分段都是统一的动画曲线效果。

对象模式关键帧动画(Object keyframes)和百分比关键帧动画(Percentage keyframes)可以给每个分段设置各自的动画曲线效果。

你甚至可以设置多个ease相关的属性,看看下面这个例子:

gsap.to(".box", {
  keyframes: {
    y: [0, 80, -10, 30, 0],
   // 把关键帧整体的动画曲线设置为 'none' ,默认会跟随这个关键帧所在的tween动画设置,如果tween没设置,那么就是none
    ease: "none",
// 给关键帧的每一段动画都设置为这个动画曲线,默认是"power1.inOut"
    easeEach: "power2.inOut" 
  },
  rotate: 180,
// 这是针对这个Tween动画效果的ease,在这里只对rotate起作用,因为keyframe有自己的设置
  ease: "elastic", 
  duration: 5,
  stagger: 0.2
});

关键帧提示

Percentage keyframes动画和Object keyframes动画的行为模式有点像Tween,你可以使用onStart事件和onComplete事件。

gsap.to(".elem", {
 keyframes: [
  {x: 100, duration: 1},
  {y: 200, duration: 1, onComplete: () => { console.log('complete')}},
  {rotation: 360, duration: 2, delay: -0.25, ease: 'sine.out'}
 ]
});

gsap.to(".elem", {
 keyframes: {
  "0%":   { x: 100, y: 100},
  "75%":  { x: 0, y: 0, ease: 'power3.inOut'},
  "100%": { x: 50, y: 50, ease: 'none', onStart: () => { console.log('start')} }
 },
 duration: 2,
})

希望这个教程能帮助到你学习和使用GSAP的关键帧动画。