<!-- animation.html --> <body> <div></div> <button>Pause</button> <button>Resume</button> <script src="https://www.jb51.net/article/main.js"></script> </body>
// animation-demo.js 中插手 resume 按钮事件绑定。 document.querySelector('#resume-btn').addEventListener( 'click', () => tl.resume() );
按照我们上面讲到的逻辑,resume 最根基的领略,就是从头启动我们的 tick。那么我们就试试直接在 resume 要领中执行 this[TICK]() 会怎么样。
resume() { this[TICK](); }
在动画中,我们可以看到,假如我们直接在 resume 中执行 tick 的话,从头开始动画的盒子,并没有在本来暂停的位置开始继承播放动画。而是跳到了后头。
很显然,在我们点击 resume 的时候,我们的动画并没有记着我们暂停时候的位置。所以在我们动画暂停的同时,我们需要把 暂停的开始时间和暂停时间给记录下来。
这两个变量因为是需要在 Animation 类中利用的,所以这里要把它们界说在全局浸染域之中。那么我们就用 PAUSE_START 和 PAUSE_TIME 两个常量来生存他们。
const PAUSE_START = Symbol('pause-start'); const PAUSE_TIME = Symbol('pause-time');
接下来就是在我们暂停的时候记录一下其时的时间:
pause() { this[PAUSE_START] = Date.now(); cancelAnimationFrame(this[TICK_HANDLER]); }
其实我们记录暂停的开始时间是为了什么呢?就是为了在我们继承播放动画的时候,知道我们当下距分开始暂停的时候的时间相差了多久。
方才我们在动画里看到的现象是什么?就是我们从头启动 tick 的时候,动画的开始时间利用了当前的时间。这里说到的 “当前” 时间,就是 Timeline 已经跑到了那边。显然这个开始时间是不正确的。
假如我们在暂停的时候,记录了那一刻的时间。然后在点击 resume 的时候计较暂停开始到点击 resume 时的时长。这样我们就可以用 tick 中的 t(动画开始时间)- 暂停时长 = 当前动画应该继承播放的时间。
利用这个算法,我们就可以让我们的动画,准确的在本来暂停的位置继承开始播放了。
接下来,我们来看看代码的逻辑怎么实现:
方才我们已将在暂停的时候插手到时间记录的逻辑里,接下来我们要记录一个暂停时长。在记录暂停时长之前,我们需要一个处所给这个值赋予一个初始值为 0 。
最好的处所就是在 Timeline 开始的时候就赋予这个默认值。我们的 PAUSE_TIME 有了初始值之后,我们在执行 resume 的时候,就可以用 Date.now() - PAUSE_START 就能获得暂停动画到此刻的总时长。
这里有一个点,需要我们留意的。我们的动画大概会呈现多次暂停,而且多次的续播。那么这样的话,假如我们每次都利用这个公式计较出新的暂停时长,然后包围 PAUSE_TIME 的值,其实是不正确的。
因为我们的 Timeline 一旦开启是不会遏制的,时间一直都在流逝。假如我们每次都只是计较当前的暂停时长,回退的时间其实是差池的。而正确的方法是,每次暂停时都需要去叠加上一次暂停过的时长。这样最后回退的时间才是精确的。
所以我们赋值给 PAUSE_TIME 的时候是利用 +=,而不是包围赋值。
最后我们改革好的 Timeline 就是这样的:
export class Timeline { constructor() { this[ANIMATIONS] = new Set(); this[START_TIMES] = new Map(); } start() { let startTime = Date.now(); this[PAUSE_TIME] = 0; this[TICK] = () => { let now = Date.now(); for (let animation of this[ANIMATIONS]) { let t; if (this[START_TIMES].get(animation) < startTime) { t = now - startTime - animation.delay - this[PAUSE_TIME]; } else { t = now - this[START_TIMES].get(animation) - animation.delay - this[PAUSE_TIME]; } if (t > animation.duration) { this[ANIMATIONS].delete(animation); t = animation.duration; } if (t > 0) animation.run(t); } this[TICK_HANDLER] = requestAnimationFrame(this[TICK]); }; this[TICK](); } pause() { this[PAUSE_START] = Date.now(); cancelAnimationFrame(this[TICK_HANDLER]); } resume() { this[PAUSE_TIME] += Date.now() - this[PAUSE_START]; this[TICK](); } reset() {} add(animation, startTime) { if (arguments.length < 2) startTime = Date.now(); this[ANIMATIONS].add(animation); this[START_TIMES].set(animation, startTime); } }
我们运行一下代码看看是否正确:
这样我们就完成了 Pause 和 Resume 两个成果了。
这里我们就实现了一个可用的 Timeline 时间轴,下一篇文章我们重点去增强动画库的成果。
假如你是一个开拓者,做一个小我私家博客也是你简历上的一个亮光点。而假如你有一个超等炫酷的博客,那就越发是亮上加亮了,的确就闪闪发光。
主题 Github 地点:https://github.com/auroral-ui/hexo-theme-aurora
主题利用文档:https://aurora.tridiamond.tech/zh/