基本使用
创建一个动画
先让一个class="box"的div元素动起来
gsap.to(".box", { x: 200 })如上代码是使用gsap对象的to()方法,使类名为box的元素,从一开始的位置,平移200px(底层实现代码为transform: translateX(200px)),这个函数返回一个Tween对象,整个动画也叫做Tween补间动画
以上代码运行结果如下
可以看到,box从一开始的位置,移动到了x为200的位置
gsap.to()方法的组成部分如下

我们可以看到这句代码里面,这里有一个方法(method),一个目标(target),还有一个对象数据(variables)。
method
有四种Tween的动画方式
gsap.to():使元素从初始状态到目标状态gsap.from():使元素从目标状态到初始状态gsap.fromTo():需要自己定义两个状态的数据,然后从前一个变化到后一个。gsap.set():直接设置成想要的状态,没有任何过度与动画效果。本质上就是duration为0的 .to 方法
以下为几种方法的区别:
target
target动画的目标元素
当传入一个字符串时,底层上使用了
document.querySelector( )选择元素,所以可以用任何css选择器进行元素的选择js// 符合css选择的的字符串都可以 gsap.to(".box", { x: 200 }); gsap.to("section > .box", { x: 200 });也可以直接传入一个
Dom元素,或是一个包含多个Dom元素的数组js// 传入一个Dom let box = document.querySelector(".box"); gsap.to(box, { x: 200 }) // 使用数组传入多个Dom let square = document.querySelector(".square"); let circle = document.querySelector(".circle"); gsap.to([square, circle], { x: 200 })
variables
这个对象包含着所有动画变化相关的信息。你可以设置任意的你想要发生变化的属性和值,或者一些特殊的会影响动画过程的一些属性,比如duration(动画时长),onComplete(动画完成时触发事件)或者repeat(动画重复的次数)
gsap.to(target, {
x: 200,
rotation: 360,
duration: 2
})什么属性可以变化
几乎所有的属性gsap都可以使之成为动画,包括css属性、自定义对象属性、甚至CSS变量和复杂的字符串都可以!我们最常变化的属性其实是transform和opacity。
TIP
Transform是动画效果的最好的朋友了。它可以轻松地让元素实现移动、缩放、旋转等等效果。Transform和opacity性能也是非常好的,因为它们不会影响布局(不会引起页面布局重绘),对于浏览器来说是节约性能的。
Transform 速记
通常给一个元素添加动画,我们可能会使用以下属性
transform: rotate(360deg) translateX(10px) translateY(50%);使用Gsap,便可以简化以上写法
{ rotation: 360, x: 10, yPercent: 50 }以下为transform转化为gsap语法的简化表
| GSAP | Description or equivalent CSS | 描述 |
|---|---|---|
| x: 100 | transform: translateX(100px) | 水平平移100像素 |
| y: 100 | transform: translateY(100px) | 竖直平移100像素 |
| xPercent: 50 | transform: translateX(50%) | 水平平移自身50% |
| yPercent: 50 | transform: translateY(50%) | 竖直平移自身50% |
| scale: 2 | transform: scale(2) | 缩放自身2倍 |
| scaleX: 2 | transform: scaleX(2) | 水平缩放自身2倍 |
| scaleY: 2 | transform: scaleY(2) | 竖直缩放自身2倍 |
| rotation: 90 | transform: rotate(90deg) | 旋转90度 |
| rotation: "1.25rad" | Using Radians - no CSS alternative | 选择1.25弧度 |
| skew: 30 | transform: skew(30deg) | 倾斜30度 |
| skewX: 30 | transform: skewX(30deg) | 水平倾斜30度 |
| skewY: "1.23rad" | Using Radians - no CSS alternative | 水平倾斜1.25弧度 |
| transformOrigin: "center 40%" | transform-origin: center 40% | 设置选择中心水平中央 竖直40%位置 |
| opacity: 0 | adjust the elements opacity | 透明度 |
| autoAlpha: 0 | shorthand for opacity & visibility | 不透明度和可见性的简写 |
| duration: 1 | animation-duration: 1s | 动画的总时长 默认是0.5 |
| repeat: -1 | animation-iteration-count: infinite | 动画重复次数,-1表示无限重复 |
| repeat: 2 | animation-iteration-count: 2 | 动画重复2次 |
| delay: 2 | animation-delay: 2 | 延迟2s执行动画 默认是0.5 |
| yoyo: true | animation-direction: alternate | 动画执行完后,反向执行一次 默认是false |
下面是个小案例,可以修改左侧代码,改变右侧动画效果
TIP
默认情况下gsap会使用px和degrees作为transforms的单位,但我们也可以使用其他单位比如vw、radians,或者通过js自定义的计算的值
x: 200, //直接传入数字的话默认就是px单位
x: "+=200" // 通过+=的方式是一种相对值,这里是在元素当前基础上再移动200px
x: '40vw', // 也可以传入其他的CSS中的单位,比如这里用的视口宽度单位 vw
x: () => window.innerWidth / 2, // 也可以用函数,只要能返回数字或者相应的表示属性对应值的字符串
rotation: 360 // 旋转如果直接输入数字的话默认是degree的单位,既角度值单位
rotation: "1.25rad" // 如果你要弧度值,就要这么写css属性
gsap可以通过修改css属性实现动画,注意属性名需要使用小驼峰
TIP
虽然GSAP几乎什么CSS属性都能实现变化,但是我们更推荐使用transform和opactiy相关的属性。因为其他属性比如像Filter和boxShadow这些是和设备的GPU性能密切相关的。如果你要使用这些属性,那么你得考虑你的代码在性能比较差的设备上的运行情况。
svg属性
和HTML元素类似,SVG元素也可以通过一些简化的transform属性来进行动画设置。另外,你还可以驱动SVG的其他一些属性,比如width,height,fill,stroke,cx,opacity甚至是SVG的viewBox属性,要实现以上效果你要用一个attr属性,传入一个对象进行设置。
对象属性
GSAP可以变化任何对象的属性
let obj = { myNum: 10, myColor: "red" };
gsap.to(obj, {
myNum: 200,
myColor: "blue",
onUpdate: () => console.log(obj.myNum, obj.myColor)
});Canvas
在下面的这个案例中,我们通过HTML的canvas元素绘制了一个方块。
我们让保存在position对象中的x和y的值发生变化,然后通过动画刷新的函数来更新canvas中绘制的元素的数据,从而达到让这种canvas绘制的元素也能被GSAP驱动。
这也是GSAP用来配合Threejs,HTML canvas以及Pixijs的使用的工作逻辑。
特别的属性
调整一个tween动画的表现,我们可以通过一些特别的属性进行设置。实际上,我们已经看过一个了,就是duration
以下是一些常用的属性,也可以前往文档查看所有属性
| 属性 | 描述 |
|---|---|
| duration | 动画变化的时长(秒)默认是0.5 |
| delay | 动画变化开始前的延迟时长(秒),默认是0.5 |
| repeat | 动画的重复次数 |
| yoyo | 如果设置为ture,那么动画会在执行完之后再反向执行一次,就像悠悠球的效果,默认是false |
| stagger | 是一个时间的设置(秒),如果有多个元素同时要被驱动,那么当这个属性设置了时间的值之后,元素们会被依次逐个驱动,间隔时长就是这个属性设置的时长 |
| ease | 动画过渡的运动曲线的设置,默认是"power1.out" |
| onComplete | 动画结束时执行的回调函数 |
重复和交替运动
repeat可以让一个动画重复执行,repeat搭配yoyo可以实现一种多次的来回动画
延迟Delays
你可以通过delay设置让动画开始前有一定的延迟时间(秒数)。你也可以使用repeatDelay来设置每次重复动画时间间隙(秒)。
Easing 动画曲线
Easing动画曲线可以让一个动画更加的灵动
以下是两个小例子,一个没有动画曲线,一个设置了gsap自带的名为bounce.out的动画曲线
除此之外,官方有更多种类的动画曲线
Staggers 交错动画
通过GSAP能非常轻松实现依次动画的效果。如果你有很多个需要动起来的元素,那么你可以很轻松的给这些元素加上一种依次启动的效果。
甚至可以通过网格布局的方式让元素也产生依次变化的动画下过,只要你告诉GSAP一共有几行几列就可以了!
高级配置
若想实现更加复杂的交错动画,stagger不仅可以传入一个以秒为单位的数值,也可以传入一个对象,
gsap.to('.box', {
y: 100,
stagger: {
each: 0.1,
from: 'center',
grid: 'auto',
ease: 'power2.inOut',
repeat: -1
}
});对象可以包含如下属性:
| 属性 | 类型 | 描述 |
|---|---|---|
| amount | Number | 所有交错元素动画的总时间(秒),若值为1,且有100个元素,则每个元素交错的时间为0.01s |
| each | Number | 每个元素执行交错动画所需要的时间,若值为1,则所有元素交错时间都为1s |
| from | String|Numebr|Array | 规定交错动画的元素数组(querySelectorAll获取的数组)中,哪个位置的元素开始执行动画 数值类型:若值为4,则从下标为4的元素开始交错 字符串类型:可以是"start"、"center"、"edge"、"random"、"end" 如果使用了grid定制了网格交错布局,则可以使用数组规定开始交错位置:例如[0.5,0.5]为中心,[1,0] 是右上角。 默认值为0 |
| grid | Array|"auto" | 若需要交错元素以网格形式布局,使用数组指示出元素有多少行多少列,例如[9, 15](9行15列。或者使用"auto",让元素自动计算(getBoundingClientRect()),这比较适合响应式布局,网格默认是从左上角至右下角 |
| axis | String | 如果使用网格布局,交错动画是基于每个元素到x轴和y轴的from值的总距离,如果只想关注一个轴,可以单独给一个字符串"x"或"y" |
| ease | String|Function | 规定了动画的动画曲线。默认值"none" |
函数
当需要自定义交错逻辑时,可以使用函数定义,该函数为数组中的每个元素调用一次,并应返回从起始位置开始的总延迟(而不是前一个tween开始时间的延迟量)
gsap.to('.box', {
y: 100,
stagger: function (index, target, list) {
// 书写自定义逻辑,返回值为交错的开始延迟时间
return index * 0.1;
}
});参数:
index- 交错元素的下标target- 交错元素本身dom元素list-交错元素的总数组
Repeat / Yoyo / Callbacks
当repeat和stagger两个属性处于同一层级时,动画的重复会发生在整个动画结束后
gsap.to(... {repeat:-1, stagger:{...})若repeat属于stagger里的属性,则交错队列的每一个子元素动画结束后,会单独的重复动画
gsap.to(... {stagger:{repeat:-1, ...}});同样yoyo和callback也是这个道理
Sequencing 排序动画
像上面我们刚学习的错开动画的效果,其实可以用在不同的场景中。但是如果我们想要让这种错开或者依次进行的动画效果有更强的可控性和灵活性,该怎么办呢?最原始的办法应该是使用delay这个属性。
但是使用delay属性来实现依次动画的这种方式本身是很脆弱的。假如我们需要修延长第一个元的动画时长,那么第二个元素需要我们进行重新设置,第三个元素也需要我们进行重新设置,这样就会非常麻烦也很低效,因此我们创造了时间线timeline这个东西
Timelines 时间线动画
时间线是可以用来方便快捷的创建各种依次进行的动画效果的能力。当你把多个tween动画效果添加到时间线上,默认他们就会按照他们添加的顺序依次执行。
// 创建Timeline类型的实例
let tl = gsap.timeline()
// 把tween动画添加到timeline实例上,然后我们这里用tl.to去驱动动画,而不是gsap.to
tl.to(".green", { x: 600, duration: 2 });
tl.to(".purple", { x: 600, duration: 1 });
tl.to(".orange", { x: 600, duration: 1 });如果我们想要在动画之间加一个停顿或者说间隔改
let tl = gsap.timeline()
tl.to(".green", { x: 600, duration: 2 });
tl.to(".purple", { x: 600, duration: 1, delay: 1 });
tl.to(".orange", { x: 600, duration: 1 });位置参数
这个参数能帮我们方便的实现执行顺序和执行时间点的精确控制,我们来看下这个demo
let tl = gsap.timeline()
// 绿色方块会在整个时间线开始1秒后进行移动
tl.to(".green", { x: 600, duration: 2 }, 1);
// 紫色方块会和之前一个添加的动画同时开始运动
tl.to(".purple", { x: 600, duration: 1 }, "<");
// 橘色方块会在之前所有动画都结束一秒后再开始运动
tl.to(".orange", { x: 600, duration: 1 }, "+=1");我们可以使用各种写法——绝对的秒数,百分比,相对值等等方式来决定tween动画在什么时候开始。你可以试试下面这个demo。
特殊属性
Timelines可以设置的动画属性和tween动画绝大部分是一样的,比如像repeat和delay,可以让你轻松的设定整个顺序动画的动画属性。
时间线的默认设置
如果你发现自己总是一遍又一遍的写同一个属性,那么你可以使用 defaults来进行设置。任何添加到时间线上的defaults的属性,都会被添加到这个时间线上的tween动画继承,像是通过to(),from()和fromTo()方式添加到时间线上的动画效果都是有这个继承效果的。利用这个方式可以让你的代码更简洁一些。
var tl = gsap.timeline({defaults: {duration: 1}});
//这样每个动画都是1秒的时长,不用重复写了
tl.to(".green", {x: 200})
.to(".purple", {x: 200, scale: 0.2})
.to(".orange", {x: 200, scale: 2, y: 20});控制函数
我们之前讲的动画效果都是页面加载后就启动或者延迟一定时间启动。但是如果我们想要对动画有更多一点的控制能力的话该怎么做呢?
比较常见的就是比如说我们想要点击某个按钮或有了某个交互行为之后才会让元素进行动画效果。那么控制动画的几个方法呢可以帮我们实现这个需求,在tween和timeline上都有这些方法,play,pause,reverse或者是加速变化。
// 通过一个变量保存对Tween或者Timeline实例的引用
let tween = gsap.to("#logo", {duration: 1, x: 100});
// 暂停
tween.pause();
// 恢复(继续)
tween.resume();
// 反向变化
tween.reverse();
// 直接切换到整个动画变化时长的0.5秒的时间点的状态
tween.seek(0.5);
// 直接切换到整个变化过程的1/4的节点的状态
tween.progress(0.25);
// 让运动减速到0.5倍
tween.timeScale(0.5);
// 让变化加速到原来的2倍
tween.timeScale(2);
// 直接销毁tween实例,让垃圾回收机制可以处理该实例所占用的内存
tween.kill();生命周期
一个动画有开始有结束,在相应的时间节点会触发如下钩子函数
onComplete:动画结束时触发onStart:动画开始时触发onUpdate:只要动画运行,每一帧都会触发(元素有属性变化时)onRepeat:每次动画重复时触发onReverseComplete:当动画反向执行后运动到变化起始点时触发
gsap.to(".class", {
duration: 1,
x: 100,
onComplete: () => console.log("the tween is complete")
}
gsap.timeline({onComplete: tlComplete});
function tlComplete() {
console.log("the tl is complete");
// 更多代码
}