完成本系列的前三个教程后,您现在应该对很多 Anime.js 功能感到非常熟悉。第一个教程向您展示了如何选择目标元素。在第二个教程中,您了解了不同类型的参数,这些参数可用于对不同元素的动画的延迟和持续时间进行精细控制。第三个教程的重点是学习如何在动画过程中更好地控制单个属性的值。
在本教程中,您将了解可用于根据动画进度执行函数的不同回调。几乎前面教程中的每个示例都使用css属性来演示不同的方法和参数是如何工作的。这可能使您认为该库更适合动画 CSS 属性。这一次,我们将有一个部分专门用于在 Anime.js 中创建与svg相关的有趣动画。
回调
正如我在介绍中提到的,您可以使用回调来根据动画的进度执行函数。有四种不同的回调: begin
、run
、update
和complete
。每个回调函数在特定时间触发,每个回调函数都接受一个动画对象作为其参数。
该begin()
函数在动画实际开始时调用。这意味着如果动画有 800 毫秒的延迟,begin()
只有在延迟结束后才会调用。您可以检查动画是否已开始播放或未使用animationName.begin
,分别返回true
或false
。
run
回调可用于在动画实际开始播放后的每一帧中执行一个函数。如果你想从动画的一开始就在每一帧中执行一个函数,而不考虑它的delay
,你应该使用update
回调来代替。
complete
回调与动画类似,只是begin
它在动画播放完毕后被调用。就像begin
,您可以使用animationName.complete
来检查动画是否已播放完毕。
您已经在第一个教程中看到了如何在动画 javascript 对象的数值update
时使用回调。在本教程中,我们将修改该示例并了解如何将所有这些回调一起使用以向用户提供更多信息。
var filesScanned = { count: 0, infected: 0 }; var scanCount = document.queryselector(".scan-count"); var infected = document.querySelector(".infected-count"); var scanning = anime({ targets: filesScanned, autoplay: false, count: 100, infected: 8, delay: 1000, duration: 2000, easing: "linear", round: 1, update: function(anim) { if (anim.currentTime < 1000) { document.querySelector(".update-cb").innerhtml = "Creating an Index..."; } }, begin: function() { document.querySelector(".begin-cb").innerHTML = "Starting the Scan..."; }, run: function() { scanCount.innerHTML = filesScanned.count; infected.innerHTML = filesScanned.infected; }, complete: function() { document.querySelector(".complete-cb").innerHTML = "Scan Complete..."; } });
我故意在这个动画中添加了一些延迟,以便我们可以注意到不同回调执行时间的差异。update
一旦动画实例开始,回调就会开始执行其函数 。
实际动画在 1000 毫秒后开始播放,此时begin
函数向用户显示其“开始扫描...”消息。该run
函数也同时开始执行,并在每一帧之后更新对象的数值。动画完成后,complete
回调会向用户显示“扫描完成...”消息。
缓动函数
缓动函数可用于控制属性值如何从初始值转换为最终值。这些缓动函数可以使用 easing 参数指定,该参数可以接受字符串以及自定义贝塞尔曲线坐标(以数组的形式)。
有 31 种不同的内置缓动函数。其中一个是linear
,另外 30 个由 、 和 的十个不同变 easeIn
体easeOut
组成easeInOut
。共有三个弹性缓动方程,分别称为 easeInElastic
、 easeOutElastic
和 easeInOutElastic
。您可以使用参数控制它们的弹性elasticity
。的值elasticity
可以是 0 到 1000 之间的任何值。
EaseIn
方程从零开始加速属性的值变化。这意味着价值的变化在开始时会很慢,最后会很快。变化率在开始时为零,在结束时最大。EaseOut
方程从最大速率变化开始减速属性的值变化。
这意味着价值的变化在开始时会非常快,在结束时会非常缓慢。EaseInOut
方程在开始时加速速率变化并在结束时减速。这意味着变化的速度在开始和结束时都会很慢,而在动画中间会最快。以下演示显示了每个缓动函数的变化率差异。
您还可以借助anime.easings
. 这是创建自定义缓动函数的示例。
anime.easings['tanCube'] = function(t) { return Math.pow(Math.tan(t*Math.PI/4), 3); } anime.easings['tanSqr'] = function(t) { return Math.pow(Math.tan(t*Math.PI/4), 2); } var tanCubeSequence = anime({ targets: '.tan-cube', translateX: '75vw', duration: 2000, easing: 'tanCube', autoplay: false }); var tanSqrSequence = anime({ targets: '.tan-sqr', translateX: '75vw', duration: 2000, easing: 'tanSqr', autoplay: false });
基于 SVG 的动画
到目前为止,我们创建的所有与运动相关的动画都以直线移动目标元素。在 Anime.js 中也可以沿着具有大量曲线的复杂 SVG 路径移动元素。您可以控制路径上动画元素的位置和角度。要将元素移动到路径的 x 坐标,可以使用 path(x)
. 类似地,可以使用 . 根据路径的 y 坐标移动元素path(y)
。
除非路径是一条直线,否则它几乎总是相对于水平基线形成一个角度。如果您正在旋转任何非圆形元素,如果元素遵循路径的角度会感觉更自然。您可以通过将rotate
属性设置为等于 来做到这一点path('angle')
。这是沿 SVG 路径为具有不同缓动值的四个元素设置动画的代码。
var path = anime.path('path'); var easings = ['linear', 'easeInCubic', 'easeOutCubic', 'easeInOutCubic']; var motionPath = anime({ targets: '.square', translateX: path('x'), translateY: path('y'), rotate: path('angle'), easing: function (el, i) { return easings[i]; }, duration: 10000, loop: true });
您可以在下面的演示中看到,带有easeInCubic
缓动的红色方块在开始时最慢,在结束时最快。类似地,橙色方块easeOutCubic
在开始时最快,在结束时最慢。
您还可以使用 Anime.js 为不同 SVG 形状的变形制作动画。唯一的条件是两个形状应具有相同数量的点。这意味着您只能将三角形变形为其他三角形,将四边形变形为其他四边形。尝试在数量不等的多边形点之间变形会导致形状突然变化。这是变形三角形的示例。
var morphing = anime({ targets: 'polygon', points: [ { value: '143 31 21 196 286 223' }, { value: '243 31 21 196 286 223' }, { value: '243 31 121 196 286 223' }, { value: '243 31 121 196 386 223' }, { value: '543 31 121 196 386 223' } ], easing: 'linear', duration: 4000, direction: 'alternate', loop: true });
您可以使用 SVG 创建的另一种有趣的效果是线条绘制。您所要做的就是为 Anime.js 提供您想要用于线条绘制的路径以及控制其持续时间、延迟或缓动的其他参数。在下面的演示中,我使用回调将font Awesome 锚图标complete
的线条绘制填充为黄色。
var lineDrawing = anime({ targets: 'path', strokeDashoffset: [anime.setDashoffset, 0], easing: 'easeInOutCubic', duration: 4000, complete: function(anim) { document.querySelector('path').setAttribute("fill", "yellow"); } });
结合您迄今为止所学的所有概念的知识,您可以创建更复杂的线条图,并更好地控制它们的绘制方式。这是一个示例,其中我使用 SVG 编写了自己的名字。
var letterTime = 2000; var lineDrawing = anime({ targets: "path", strokeDashoffset: [anime.setDashoffset, 0], easing: "easeInOutCubic", duration: letterTime, delay: function(el, i) { return letterTime * i; }, begin: function(anim) { var letters = document.querySelectorAll("path"), i; for (i = 0; i < letters.length; ++i) { letters[i].setAttribute("stroke", "black"); letters[i].setAttribute("fill", "none"); } }, update: function(anim) { if (anim.currentTime >= letterTime) { document.querySelector(".letter-m").setAttribute("fill", "#e91e63"); } if (anim.currentTime >= 2 * letterTime) { document.querySelector(".letter-o").setAttribute("fill", "#3F51B5"); } if (anim.currentTime >= 3 * letterTime) { document.querySelector(".letter-n").setAttribute("fill", "#8BC34A"); } if (anim.currentTime >= 4 * letterTime) { document.querySelector(".letter-t").setAttribute("fill", "#FF5722"); } if (anim.currentTime >= 5 * letterTime) { document.querySelector(".letter-y").setAttribute("fill", "#795548"); } }, autoplay: false });
我首先将值 2000 分配给变量letterTime
。这是我希望 Anime.js 绘制我名字的每个字母的时间。该属性使用基于函数的索引参数在变量的帮助下delay
设置适当的值。 delay
letterTime
第一个字母“M”的索引为零,因此 Anime.js 立即开始绘制它。字母“O”有 2000 毫秒的延迟,因为这是完全绘制字母“M”所需的时间。
在begin
回调中,我将stroke
所有字母的值设置为 ,black
并将它们的fill
值设置为none
。这样我们可以清除update
回调中应用的所有颜色值,以便字母在多个循环中运行时可以返回到它们的初始状态。尝试单击以下演示中的写入名称按钮以查看实际代码。
最后的想法
在本教程中,您了解了不同的回调函数,它们可用于执行诸如更新dom或根据动画进度更改属性值等任务。您还了解了不同的缓动函数以及如何创建自己的缓动函数。本教程的最后一部分侧重于创建基于 SVG 的动画。