使用JavaScript 实现时间轴与动画效果的示例代码(2)

还有一个就是,一旦我们这个 tick 写的不好,setInterval 就有可能发生积压。因为它是固定 16 毫秒循环执行的,所以 interval 之间是不会管上一个 interval 中的代码是否已经执行完,第二个 interval 的代码就会进入 interval 的队列。这个也是取决于浏览器的底层实现,每一个浏览器有可能选择不同的策略。

因为我们这里实现的动画库,不需要考虑到旧浏览器的兼容性。我们这里就选择使用 requestAnimationFrame。

接下来的时间轴库中,我们就会使用 requestAnimationFrame 来做一个自重复的操作。

这里还要提到一个和 requestAnimationFrame 对应的一个 cancelAnimationFrame。如果我们声明一个变量来储存 requestAnimationFrame,我们就可以传入这个变量到 cancelAnimationFrame 让这个动画停止。

let tick = () => { let handler = requestAnimationFrame(tick); cancelAnimationFrame(handler); }

这样我们就可以避免一些资源的浪费。

实现 Timeline 时间轴

开头我们讲过,在做动画的时候,我们就需要把 tick 这个东西给包装成一个 Timeline。

接下来我们就来一起实现这个 Timeline(时间轴) 类。正常来讲,我们一个 Timeline 只要 start(开始)就可以了,并不会有一个 stop(停止)的状态。因为一个时间轴,肯定是会一直播放到结束的,并没有中间停止这样的状态。

不过它是会有 pause(暂停) 和 resume(恢复)这种组合。而这一组状态也是 Timeline 中非常重要的功能。比如,我们写了一大堆的动画,我们就需要把它们都放到同一个动画 Timeline 里面去执行,而在执行的过程中,我可以让所有这些动画暂停和恢复播放。

另外就是这个 rate(播放速率),不过这个不是所有的时间线都会提供。rate 会有两种方法,一个是 set、一个是 get。因为播放的速率是会有一个倍数的,我们可以让动画快进、慢放都是可以的。

在设计这个动画库时,还有一个非常重要的概念,叫 reset(重启)。这个会把整个时间轴清理干净,这样我们就可以去复用一些时间线。

这个教程中实现的 set 和 get 的 rate 就不做了,因为这个是比较高级的时间线功能。如果我们要做这个就要讲很多相关的知识。但是 pause 和 resume 对于我们的 carousel(轮播图)是至关重要的,所以这里我们是一定要实现的。

讲了那么多,我们赶紧开工吧!~

实现 start 函数

在我们的 start 方法中,就会有一个启动 tick 的过程。这里我们会选择把这个 tick 变成一个私有的方法(把它藏起来)。不然的话,这个 tick 谁都可以调用,这样很容易就会被外部的使用者破坏掉整个 Timeline 类的状态体系。

那么我们怎么才能把 tick 完美的藏起来呢?我们会在 animation.js 这个文件的全局域中声明一个常量叫 TICK。并且用 Symbol 来创建一个 tick。这样除了在 animation.js 当中可以获取到我们的 tick 之外,其他任何地方都是无法获得 tick 这个 Symbol 的。

同理 tick 中的 requestAnimationFrame 也同样可以创建一个全局变量 TICK_HANDLER 来储存。这个变量也会使用一个 Symbol 来包裹起来,这样就可以限定只能在本文件中使用。

对 Symbol 不是很熟悉的同学,其实我们可以理解它为一种 “特殊字符”。就算我们把两个传入 Symbol 的 key 都叫 ‘tick',创建出来的两个值都会是不一样的。这个就是 Symbol 的一个特性。

其实我们之前的《前端进阶》的文章中也有详细讲过和使用过 Symbol。比如,我们使用过 Symbol 来代表 EOF(End Of File)文件结束符号。所以它作为对象的一个 key 并不是唯一的用法,Symbol 这种具有唯一特性,是它存在的一个意义。

有了这两个常量,我们就可以在 Timeline 类的构造函数中初始化 tick。

初始化好 Tick 我们就可以在 start 函数中直接调用全局中的 TICK。这样我们 Timeline(时间线)中的时间就开始以 60 帧的播放率开始运行。

最后代码就是如下:

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wsdgjx.html