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

这个变化值,就相等于我们 CSS animation 中的 linear 动画曲线。这动画曲线就是一条直线。这里我们先用这个实现我们的 Animation 类,就先不去处理我们的 timingFunction,后面我们再去处理这个动态的动画曲线。

有了这个变化值,我们就可以用 startValue(初始值)+ 变化值,得到当前进度对应的属性值。我们的代码就是这样实现的:

run(time) { let range = this.endValue - this.startValue; this.object[this.property] = this.startValue + (range * time) / this.duration; }

这样 Animation 就可以运作的了。接下来我们把这个 Animation 添加到 Timeline 的 animation 队列里面,让它在队列中被执行。

我们上面说到,这个 Animation 中的 run 方法接收的 time(时间)是一个虚拟的时间。所以在 Timeline 中调用这个 run 方法的时候就要把一个虚拟时间传给 Animation,这样我们的动画就可以运作了。

好,这里我们要添加 animation 到 timeline 里面,首先我们就要有一个 animations 队列。这个我们就直接生成一个 animations Set。

这个与其他 Timeline 中的储存方式一样,我们建立一个全局的 ANIMATIONS 常量来储存,它的值就用 Symbol 包裹起来。这样就可以避免这个队列不小心被外部调用到了。

const ANIMATIONS = Symbol('animations');

这个队列还需要在 Timeline 类构造的时候,就赋值一个空的 Set。

constructor() { this[ANIMATIONS] = new Set(); }

有队列,那么我们必然就需要有一个加入队列的方法,所以我们在 Timeline 类中还要加入一个 add() 方法。实现逻辑如下:

constructor() { this[ANIMATIONS] = new Set(); }

我们要在 Timeline 中给 Animation 的 run 传一个当前已经执行了的时长。要计算这个时长的话,就要在 Timeline 开始的时候就记录好一个开始时间。然后每一个动画被触发的时候,用 当前时间 - Timeline 开始时间 才能获得当前已经运行了多久。

但是之前的 tick 是写在了 constructor 里面,Timeline 开始时间必然是放在 start 方法之中,所以为了能够更方便的可以获得这个时间,我们可以直接把 tick 声明放到 start 里面。

虽然说这个改动会让我们每次 Timeline 启动的时候,都会重新构建一个 tick 对象函数。但是这种方法会更便于快速实现这个功能,不过想要性能更好的同学也是可以优化这一个地方的。

移动完我们 tick 之后,我们就可以在 tick 里面加入调用 ANIMATIONS 队列的 animation(动画)了。因为一个 Timeline 里面可以有多个animation,并且每一帧都会推动他们到下一个进度的属性状态。所以这里我们就用一个循环,然后调用一遍我们 ANIMATIONS 队列里面的所有的 animation 的 run 方法。

最后我们的代码就是这样的:

const TICK = Symbol('tick'); const TICK_HANDLER = Symbol('tick-handler'); const ANIMATIONS = Symbol('animations'); export class Timeline { constructor() { this[ANIMATIONS] = new Set(); } start() { let startTime = Date.now(); this[TICK] = () => { let t = Date.now() - startTime; for (let animation of this[ANIMATIONS]) { animation.run(t); } requestAnimationFrame(this[TICK]); }; this[TICK](); } pause() {} resume() {} reset() {} add(animation) { this[ANIMATIONS].add(animation); } } export class Animation { constructor(object, property, startValue, endValue, duration, timingFunction) { this.object = object; this.property = property; this.startValue = startValue; this.endValue = endValue; this.duration = duration; this.timingFunction = timingFunction; } run(time) { console.log(time); let range = this.endValue - this.startValue; this.object[this.property] = this.startValue + (range * time) / this.duration; } }

我们在 animation 的 run 方法中,加入一个 console.log(time),方便我们调试。

最后我们在 main.js 中,把 animation 加到我们的 Timeline 中。

import { Component, createElement } from './framework.js'; import { Carousel } from './carousel.js'; import { Timeline, Animation } from './animation.js'; let gallery = [ 'https://source.unsplash.com/Y8lCoTRgHPE/1600x900', 'https://source.unsplash.com/v7daTKlZzaw/1600x900', 'https://source.unsplash.com/DlkF4-dbCOU/1600x900', 'https://source.unsplash.com/8SQ6xjkxkCo/1600x900', ]; let a = <Carousel src=https://www.jb51.net/{gallery} />; // document.body.appendChild(a); a.mountTo(document.body); let tl = new Timeline(); // tl.add(new Animation({}, 'property', 0, 100, 1000, null)); tl.start();

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

我们发现 Animation 确实可以运作了,时间也可以获得了。但是也发现了一个问题,Animation 一直在播放没有停止。

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

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