TimelineMax:Tweening简介
在以前,动画Tweening是描述一帧一帧序列的术语,有时候也被称为 in-between
。放置在一个运动结束,要进行下一个运动前,中间创建一个流畅的过渡。年纪比较大的同学可能会记得Flash;这个应用程序在引用帧移动时使用了这个术语。我们先来仔细观察几个示例。
TweenMax创建的Tweening
在本教程的两个示例中,我都加载了 TweenMax.min.js ,以获取 TimelineMax
,以及所有 GSAP 提供的核心工具。回想一下这系列教程的TimelineMax入门篇,我说到的加载 TweenMax.min.js
是因为这比较方便,只加载一个文件就可以包含所有我们需要的东西(这也是GreenSock一直推荐的)。
TweenMax 扩展了 TweenLite ,加入了许多有用的(但非必须)功能,如 repeat()
、 repeatDelay()
、 yoyo()
、 updateTo()
等等。TweenMax是为了方便而创建的,提供了一个单独的javascript文件,包含了所有你需要的用于操纵DOM元素的内容。它还允许作者们去制定单个动作,而 TimelineMax 将接受链式方法来创建一组更复杂的补间/序列。
loader序列
loader就是当用户在等待某个进程/程序加载的过程中播放的对象。这里我们可以去探索小个的、微小尺寸的元素,使得它们可以有复杂的甚至简单的互动,它们都可以做到。
快速浏览一下下面的这个“珍珠串”示例:
我们把序列打散,便于理解这一整个补间动画的工作原理。
为了创建这个序列,我们需要使用 staggerTo 方法。如果你想不起这个方法是什么,我建议你就此打住,先看看我的上一篇教程。
根据GreenSock文档, staggerTo()
方法:
“tweens an array of targets to a common set of destination values.
在这里这组对象指的是SVG标签内的所有圆。
staggerTo
的第一个参数接受的是我们圆的选择器(在这里,circle
)。- 第二个参数是Tweening动画的持续时间(整个动画的持续时间)。
- 第三个参数是包含补间动画属性配置的对象字面量。
- 最后一个参数用于保存我们的
stagger
值(每个对象各自的动画开始之间的时间)。
也就是说,假设 circles
元素包含了三个对象:
timeline.staggerTo(circles, 15, {x:0}, 0.2) // circle 1 在0s开始 // circle 2 在0.2s开始 // circle 3 在0.4s开始
loader设置
在开始前,我们需要定义一个新的时间轴,以及设置一些配置。
var loader = new TimelineMax({ repeat: -1, yoyo: true }), circles = $('svg circle'), stagger_options = { opacity: 0, y: -800, ease: Elastic.easeInOut };
为了使得这个时间轴在相反的方向重复,我使用了 yoyo
,并把它的值设置为 true
。所以,这可以使得我们的动画在到达最后一帧之后,就反向再次播放。触发动画需要先获取SVG中的每个圆,这也是为什么我们需要jQuery帮助来引用对象。
文档中指出了很多传递选择器的方法(可以点击 这里 阅读更多相关内容)。在这里我使用了jQuery的典型选择器语法来选中所有的圆。这里把我们的引用保存在一个对象中,方便后边重用,因此 circles = $('svg circle')
。
stagger_options
变量是一个对象字面量,包含了所有让这个动画动起来的属性。我们使用 y
来移动对象,因为GSAP CSSPlugin 智能地把 transform
值转换成等价 matrix
,最终为我们提升了速度。还有一列 transform
属性简写的列表,,相比CSS transform
更优越也更容易使用:
GSAP对应CSS属性
CSS | GSAP |
---|---|
translateX() | x |
translateY() | y |
translateZ() | z |
rotate() | rotation |
rotateY() | rotationY |
rotateX() | rotationX |
scaleX() | scaleX |
scaleY() | scaleY |
skewX() | skewX |
skewY() | skewY |
我们还可以控制 easing
(动画的播放速度),然后产生不同的运动类型。对于视觉爱好者,你可以查看GreenSock提供的 ease函数可视化文档 ,获取更多对ease变量的理解。
这个动画的最后一部分是把 staggerTo
方法赋给我们的时间轴,然后插入前面定义的变量,并按照正确的序列放置(元素,持续时间,选项, stagger
的值)。
loader.staggerTo(circles, 0.875, stagger_options, 0.025);
链上第二个Tween
在 stagger
序列完成之后,如果你还想创建另一个序列,你可以链上另一个方法,例如 fromTo
这样:
loader.staggerTo(circles, 0.875, stagger_options, 0.025) .fromTo(target: Object, duration: Number, fromVars:{}, toVars: {});
进一步讲解
我们可以尝试一下用在SVG上,也就是我说的“Polyman”。最近我在CSS-Tricks写了一篇 文章 ,关于操纵多边形动画的(w3cplus的译文),然后决定在这里使用相同的示例做另一个补间练习。我们尝试使用了 staggerFromTo()
方法,然后看看我们将创建出什么魔术。
为了方便讨论,下面的SVG输出略有删减,但你会看到我们的SVG包含了一些标签;特别是 <g>
和 <path>
。还要注意路径把人物脸上的不同器官分成了多组,以便更好地控制stagger(例如,耳朵、眼睛、鼻子……)
<svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 800 800" class="polyman"> <g id="ears"> <path fill="#E6BBBE" d="M346.5,344.2l-2.8-3.4l4.1-18.5L346.5,344.2z"></path> <path fill="#EAD9DD" d="M344,332.5l-0.3,8.3l4.1-18.5L344,332.5z"></path> <path fill="#EEDFE3" d="M346,307.1l1.8,15.2l0.4-22.1L346,307.1z"></path> </g> <!-- and so on --> </svg>
在时间轴的初始化设置中我们使用一个对象字面量定义了我们的全局选项,设置了初始动画的延迟,重复动画序列,重复动画的延迟,以及反向播放动画。
var tmax_options = { delay: 0.25, repeat: -1, repeatDelay: 0.25, yoyo: true };
Transform值的转换
接下来是一个比较新的但没有加入文档的属性,可以强制将 transform
值转换为可以放置在SVG transform
属性中的值(相对于CSS样式)。
CSSPlugin.useSVGTransformAttr = true;
加入这个属性是为了让开发者更容易捕捉Safari中的bug,当结合使用 opacity
和 transform
属性(例如 transform: scale()
)时,会产生一个奇怪的结果。但是1.16.0版本, useSVGTransformAttr
已经自动设置为 true
,是特别针对Safari的调整,所以现在你们就不再需要像我上面那样定义了。
因为 staggerFromTo
方法在 from
和 to
位置接受不同的参数,我喜欢先在方法外边设置两个对象字面量,便于组织和增加可读性。
var stagger_opts_from = { opacity: 0, scale: 0, transformOrigin: 'center center' }; var stagger_opts_to = { opacity: 1, scale: 1, ease: Elastic.easeInOut, force3D: true };
我们定义了两个对象字面量,因为动画本身我们需要按照顺序为其定义 from
和 to
属性。如果还不清楚,我们从 stagger_opts_from
中定义的值,到 stagger_opts_to
中设置的结尾来看。
force3D
强制GSAP给元素的变换应用一个3D值;也就是说使用 matrix3d()
而不是 matrix()
,是 translate3d()
而不是 translate()
。这导致了浏览器把目标元素放在复合层上,从而使得动画更有效地更新。
默认情况下 force3D
的值为 auto
(1.15.0版本),所以实际上没有必要在所有地方都使用它(除非那个补间你真的需要 true
值而不是 auto
)。
// 在补间开始的时候对对象进行分层,并让它们在适用的地方使用3D矩阵(用于二维和三维变换) force3D:true // 在补间开始的时候对对象进行分层,在补间结束的时候再合并(切换回2D矩阵或变换)。这可以防止你创建或挂起上百个分层元素(会降低性能),也可以确保文本在补间返回的期间已经栅格化。 force3D:auto
你可以使用 CSSPlugin 提供的 defaultForce3D
属性为所有补间设置全局 force3D
值。
// 也可以接受 'false' 或 'auto' CSSPlugin.defaultForce3D = true;
或者你可以对每个补间逐个进行设置:
// 在补间完成后继续保持元素的分层状态 timeline.to(element, 1, {x:300, force3D:true); // 在补间完成后继续保持元素的分层状态 timeline.to(element, 1, {x:300, force3D:false);
窗口加载时隐藏
如果你的动画试图重写CSS属性,你需要确保你的特定内容不会和你在JavaScript中声明的冲突,否则原生CSS值将具有较高的优先级,而你的动画则不能按照预期的播放。
/* Required Polyman Styles */ .polyman path { opacity: 0; }
上面的CSS隐藏了初始窗口加载时的polyman,所以我们开始的时候看不到我们的大胡子朋友,就像你可能经历过的,我们通常称为FOUT(Flash Of Unstyled Text:文本样式短暂失效)。
因为我们的大多数配置已经定义好了,我们终于可以开始设置我们的时间轴、指定SVG路径、定义一个stagger值( stagger_val
),以及最后定义整个动画的持续时长( duration
)。
var tl = new TimelineMax(tmax_options), path = $('svg.polyman path'), stagger_val = 0.0125, duration = 1.25;
就这样,在我们挥舞魔棒,施了魔法之后,我们传入了所有需要的变量,作为参数传递给 staggerFromTo
方法。
tl.staggerFromTo(path, duration, stagger_opts_from, stagger_opts_to, stagger_val, 0);
现在一个简单的polyman已经可以动起来了,而且变成了有生命的东西(当然不是真的)。很酷吧?
接下来
在我们TweenMax系列的下一篇教程中,我们将看看如何在时间轴上创建一个暂停的点,这样动画可以在进行到某个点的时候自动暂停。 addPause()
方法相对比较新,可以让你在时间轴上的任何位置放置一个暂停。这比使用一个回调来调用一个函数用来停止某项功能要精确多了(这是在 addPause()
出现之前采用的方法)。下次见~
感谢那些一直追随GreenSock的读者们!
本文根据 @Dennis Gaebel 的《 TimelineMax: An Introduction to Tweening 》所译,整个译文带有我们自己的理解与思想,如果译得不好或有不对之处还请同行朋友指点。如需转载此译文,需注明英文出处: http://webdesign.tutsplus.com/tutorials/timelinemax-an-introduction-to-tweening--cms-23509 。
彦子
在校学生,本科计算机专业。逗比一枚,热爱前端热爱生活,喜欢CSS喜欢JavaScript喜欢SVG,爱玩PS玩AI玩啊逗比的软件。努力向上,厚积薄发。