GSAP(专业的Web/JavaScript动画库)
这是第一篇博客,文章内容是关于GSAP动画库的使用,编写于2020年10月21日17时09分(v1.0.0)。
前言
GSAP的全名是GreenSock Animation Platform,但它的确是一个从flash时代一直发展到今天的专业动画库。
中文官网地址:TweenMax中文网(GreenSock动画平台,GSAP)
英文官网地址:GreenSock
一、引入
1、下载文件包
在官网就可以下载到TweenMax文件包,就可以拿到GSAP源码了:
下载文件包地址:https://www.tweenmax.com.cn/source/
下载并解压后可以看到有这些文件(当下版本2.1.2):
这里的TweenLite.js、TweenMax.js、TimelineLite.js和TimelineMax.js4个文件就是GSAP的一般引用库文件,不过,这几个文件还有一些重叠和包含的关系,如下图:
因此,如果想要简单地引入GSAP的主体功能,使用TweenMax.js这一个文件即可(请看前一张图中反映出的这个文件的大小)。而如果要争取更小的库文件大小,应该使用TweenLite.js(必需)+ 其他文件的组合。
这4个文件分别包含了什么东西呢?
- TweenLite是GSAP的主体核心,它用于创建基本动画,是其他各类模块的基础。一般都会搭配plugins/CSSPlugin以实现DOM元素的动画(也就是我们最熟悉的动画了)。
- TimelineLite是一个叫做时间轴的动画容器,它用于对多个动画进行有序的组织与控制。
- TimeLineMax是TimelineLite的升级版,在TimelineLite的基础之上,可以有更高级的组织与控制。
- TweenMax是GSAP集合包,除前面3个之外,还包括plugins里的常用插件以及easing里的缓动函数补充。
2、CDN
还可以使用CDN的方式:
CDN指引地址:https://www.tweenmax.com.cn/cdn/
请将x.x.x改成你需要的版本号,例如2.0.1
https://cdnjs.cloudflare.com/ajax/libs/gsap/x.x.x/TweenMax.min.js
https://cdnjs.cloudflare.com/ajax/libs/gsap/x.x.x/TweenLite.min.js
https://cdnjs.cloudflare.com/ajax/libs/gsap/x.x.x/plugins/CSSPlugin.min.js
https://cdnjs.cloudflare.com/ajax/libs/gsap/x.x.x/easing/EasePack.min.js
3、npm
使用npm/yarn安装:npm install gsap / yarn install gsap
二、TweenLite的基本动画
值动画
一切动画,都从值的变化开始。
TweenLite作为主体核心,做的就是这件事。TweenLite具体如何使用呢?请看下面这个例子:
1 2 3 4 5 6 7 8 9 10 | var obj = {<!-- --> myProp: 0 }; TweenLite.to(obj, 0.2, {<!-- --> myProp: 1, onUpdate: function() {<!-- --> console.log("[update] obj.myProp = ", obj.myProp); } }); |
TweenLite.to(target, duration, vars)是TweenLite最常用的方法,target指定动画元素,duration指定动画持续时间,vars指定动画的目标值。请注意,这里并没有操作任何DOM元素,所以和我们一般写的动画不太一样。运行一下:
可以看到,TweenLite的作用是,让obj的属性myProp从初始值0,变化到目标值1。虽然没有视觉效果,但这就是基本的值动画。
有视觉效果的css动画
TweenLite加上plugins/CSSPlugin后,就可以做我们熟悉的DOM元素的动画了。例如:
1 2 3 | TweenLite.to("#ball1", 2, {<!-- --> x: 200 }); |
效果:
GSAP用x、y表示transform的translateX和translateY。TweenLite.to(target, duration, vars)的第一个参数target可以是选择符,因此这里就是选取id为ball1的元素,执行时长为2s的动画,从当前位置移动到translateX(200px)的位置。
你可以在的第3个参数vars内添加任意css属性,它们都会被用作被选取元素的动画目标值。
延迟、缓动及动画事件
第3个参数vars内除了css属性之外,还可以指定许多具有特定意义的属性,用于配置动画。GSAP会自动根据名字来区分它们。
例如,delay和ease分别用于设置动画延迟及缓动函数:
1 2 3 4 5 | TweenLite.to("#ball1", 2, {<!-- --> x: 200, delay: 2, ease: Linear.easeNone }); |
这里的动画将延迟2s运行,而且改为线性变化(默认为Quad.easeOut)。
如果想要在动画开始,动画运行的每一帧,动画结束时分别执行对应的事件函数,使用onStart、onUpdate、onComplete。前文的值动画的例子就是通过onUpdate把值的变化打印出来的。
GSAP有专门的地址可以查询缓动函数。更多的可用特定属性,请参考官方文档。
相对值
有些时候我们可能不清楚元素当前是否已经有translate,但就是想让元素相对它原本的位置移动一段距离。这时可以用相对值,像这样:
1 2 3 | TweenLite.to("#ball1", 2, {<!-- --> x: "+=200px" }); |
类似的还有-=,按照以上写法,无论元素当前的translateX是多少,都会相对偏移200px。
其他动画方法
除to()之外,还有from()和fromTo()。单词都很简单,对吧?
from()和to()的参数及用法完全一样,只是vars里的属性定义的是动画初始值,而元素原本的属性用作动画目标值。例如:
1 2 3 4 | TweenLite.from("#ball1", 2, {<!-- --> x: "+=200px", backgroundColor: "#2196f3" }); |
效果:
这里可以看到,颜色动画也是可用的。
TweenLite.fromTo(target, duration, fromVars, toVars)的参数要多1个,不过从字面意思就很容易理解,即分别让你指定动画的初始和结尾。需要注意的是,前面提到的具有特定意义的属性,如delay,ease,都要写在toVars里,在fromVars里定义的无效。
动画保存及控制
和jQuery.animate()的风格不同,GSAP以动画为主体,你可以这样保存动画:
1 2 3 | var tween = TweenLite.to("#ball1", 2, {<!-- --> x: "+=200px" }); |
然后你可以做精细的控制:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | // 暂停 tween.pause(); // 继续播放 tween.resume(); // 反转播放 tween.reverse(); // 跳转到1s进度处开始播放 tween.seek(1); // 重播 tween.restart(); // 动画变为三倍速 tween.timeScale(3); |
这些可以看做GSAP作为专业动画库的体现。
选择器
前面的例子中反复用到了类似jQuery的选择器,但GSAP并没有自带选择器,相关源码如下:
1 2 3 4 5 6 7 8 9 10 11 | TweenLite.selector = window.$ || window.jQuery || function(e) {<!-- --> var selector = window.$ || window.jQuery; if (selector) {<!-- --> TweenLite.selector = selector; return selector(e); } return (typeof(document) === "undefined") ? e : (document.querySelectorAll ? document.querySelectorAll(e) : document.getElementById((e.charAt(0) === "#") ? e.substr(1) : e)); }; |
GSAP不依赖jQuery,但如果引入了jQuery,GSAP会使用jQuery的选择器,否则回退到document.querySelectorAll()及document.getElementById()。
三、TimelineLite的动画管理
好像TweenLite + css plugin就已经足够用了,这个Timeline系列是做什么的呢?
想象你是一个动画的导演,你要按剧本安排演员在一个CUT里依次上场和退场。在前文的例子里,我们只有一个演员(#ball1),但现在,我们要拍一个有20+演员的动画大片,要怎么办呢?
你也许曾用css3的animation做过类似的事情,做法是,当转换到一个场景(CUT)后,为场景里的所有演员依次设定适当的delay。只要delay计划好,看起来就是漂亮精彩的大片。
不过,这可没有那么简单,假如你已经安排好了20位演员的上场时间,现在改了下剧本,来了第21位演员要在最开始上场,你会发现你可能要依次调整在它之后的所有演员的delay…
GSAP的TweenLite也会有同样的问题,因此,我们需要有一个工具来统一管理多个元素的多个动画,这就是TimelineLite。
时间轴
如果你做过视频编辑,你一定很熟悉“时间轴”这个概念。简单来说,每一个元素的单次动画都是一段素材,我们需要把它们分别放置到同一个时间轴的适当位置,才能集合在一起得到有序的动画大片。
现在我们引入TimelineLite。下面是一个例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | var tl = new TimelineLite(); tl.from("#ball1", 1, {<!-- --> y: "-=60px", autoAlpha: 0 }).from("#ball2", 1, {<!-- --> x: "+=60px", autoAlpha: 0 }).from("#ball3", 1, {<!-- --> y: "+=60px", autoAlpha: 0 }).from("#ball4", 1, {<!-- --> x: "-=60px", autoAlpha: 0 }); |
效果是:
以上的tl.from()等同于以下代码:
1 2 3 4 | tl.add(TweenLite.from("#ball1", 1, {<!-- --> y: "-=60px", autoAlpha: 0 })); |
可见,TimelineLite像一个容器,它可以通过add()方法将TweenLite动画添加到自己的时间轴上。然后,动画将以时间轴为整体,进行播放。
在默认情况下,TimelineLite会这样按添加顺序依次排列它们的位置,就这样,我们不借助delay做出了这种较复杂的动画组合。
如果画一下这里的时间轴,是这样的:
调整放置位置
如果要让第2个动画不是在第1个刚结束时播放,而是更提前一点,看起来更连贯的话?
这样做:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | var tl = new TimelineLite(); tl.from("#ball1", 1, {<!-- --> y: "-=60px", autoAlpha: 0 }).from("#ball2", 1, {<!-- --> x: "+=60px", autoAlpha: 0 }, "-=0.7").from("#ball3", 1, {<!-- --> y: "+=60px", autoAlpha: 0 }, "-=0.7").from("#ball4", 1, {<!-- --> x: "-=60px", autoAlpha: 0 }, "-=0.7"); |
其中tl.from(target, duration, vars, position)等同于tl.add(TweenLite.from(target, duration, vars), position);,这里的position参数指定动画在时间轴上的位置,默认为+=0也就是取前一个动画的结束点。以上的-=0.7就是相对这个位置再提前0.7s,这样就让动画互相之间有了重叠,看起来更连贯流畅一些。
效果:
时间轴像这样:
时间轴控制
把多个动画装进时间轴的重要作用是,可以当做一个整体进行控制和调整。时间轴的这些方法类似TweenLite:
1 2 3 4 5 6 7 | // 在1s时间进度位置暂停 tl.pause(1); // ... (和前面tween一样) // 跳转到50%进度处 tl.progess(0.5); |
相同动画的简便方法
如果多个元素的动画是一样的,而且它们需要有规律地安排在时间轴的不同位置,那么非常适合用staggerFrom()、staggerTo()及staggerFromTo()。例如:
1 2 3 4 | tl.staggerFrom(["#ball1", "#ball2", "#ball3", "#ball4", ], 1, {<!-- --> scale: "-=0.5", autoAlpha: 0 }, 2); |
这样使用数组,就可以同时选中多个元素。
效果是:
可以看到,每一个元素按照顺序依次执行动画,间隔2s。
四、TimelineMax和TweenMax
如果你觉得还需要一些动画和时间轴的更高级功能(如同一动画间隔重复),可以选择TimelineMax和TweenMax。它们并不需要更多的学习成本,如字面意思所示,TweenMax是TweenLite的升级版,拥有其全部特性,只是增加了一些额外的高级控制。它们的语法完全一致,你可以试试用全局搜索把所有TweenLite替换成TweenMax,不会有任何影响。TimelineMax和TimelineLite的关系也是如此。
五、补充
指定默认缓动
如果你大部分动画都使用同一种缓动函数,那么用TweenLite.defaultEase会很方便,比如修改为Expo.easeOut:
1 | TweenLite.defaultEase = Expo.easeOut; |
动画结束后清空style属性
默认情况下,执行过动画的元素会留下style的内联样式,如果你担心这可能造成额外影响,可以设定clearProps参数清空它:
1 2 3 4 5 | TweenLite.to("#ball1", 2, {<!-- --> x: 200, clearProps: "all", autoAlpha: 0 }); |
如果只需要清理个别样式,单独写出来即可,如clearProps: “opacity”。
autoAlpha的作用
前文反复用到的autoAlpha并不是css属性,而是GSAP给定的一个特殊属性。autoAlpha是opacity和visibility这2个css属性的结合。
为什么要结合起来呢?一般来说,opacity为0的不可见元素,我们会认为它也是不可交互的(比如onclick不触发),因此附加visibility: hidden可以保证这一点。GSAP会正确处理动画过程中这2个css属性的变化。
备忘单
GSAP有一份包含丰富参考代码的备忘单(Cheat Sheet),可以帮助你节约时间。
六、结语
GSAP里的很多概念和API设计可以追溯到flash时代。虽然flash在今天已经很少被使用,但“flash动画”一词能够深入人心是有它的原因的。
可参考文章地址有:https://juejin.im/entry/6844903478234447885
文章原文:https://segmentfault.com/a/1190000005366176