You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
175 lines
3.5 KiB
175 lines
3.5 KiB
/*
|
|
author: leeenx
|
|
@ timer 对象
|
|
@ 提供 7 个API如下:
|
|
@ timer.setTimeout(fun, delay[, id])
|
|
@ timer.clearTimeout(id)
|
|
@ timer.setInterval(fun, delay[, id])
|
|
@ timer.clearInterval(id)
|
|
@ timer.delete(id) 删除对应id的timeout/interval
|
|
@ timer.pause(id) 暂停对应id的timeout/interval
|
|
@ timer.resume(id) 恢复对应id的timeout/interval
|
|
@ timer.clean() 清空所有 timeout & interval
|
|
*/
|
|
|
|
class Timer {
|
|
// 构造函数
|
|
constructor() {
|
|
// 暂停状态 - 这是个公共状态,由外部 Ticker 决定。
|
|
this.paused = true;
|
|
|
|
// 队列
|
|
this.queue = new Map();
|
|
|
|
// 正在使用 timer 的 RAF
|
|
this.usingRAF = false;
|
|
|
|
// useRAF 触发器
|
|
Reflect.defineProperty(this, "useRAF", {
|
|
set: function (value) {
|
|
Reflect.set(this, "usingRAF", value);
|
|
value ? Timer.RAF.enable() : Timer.RAF.disable();
|
|
},
|
|
});
|
|
}
|
|
|
|
// setTimeout 的实现
|
|
setTimeout(fn, delay, id = Symbol("timeoutID")) {
|
|
// 存入队列
|
|
this.queue.set(id, {
|
|
fn: fn,
|
|
type: 0,
|
|
paused: 0,
|
|
elapsed: 0,
|
|
delay: delay,
|
|
});
|
|
return id;
|
|
}
|
|
|
|
// clearTimeout
|
|
clearTimeout(id) {
|
|
this.delete(id);
|
|
}
|
|
|
|
// setInterval 的实现
|
|
setInterval(fn, delay, id = Symbol("intervalID")) {
|
|
// 存入队列
|
|
this.queue.set(id, {
|
|
fn: fn,
|
|
type: 1,
|
|
paused: 0,
|
|
elapsed: 0,
|
|
delay: delay,
|
|
});
|
|
return id;
|
|
}
|
|
|
|
// clearInterval
|
|
clearInterval(id) {
|
|
this.delete(id);
|
|
}
|
|
|
|
// 修改指定id的 delay/fn
|
|
set(id, config = {}) {
|
|
let item = this.queue.get(id) || {};
|
|
for (let key in config) {
|
|
item[key] = config[key];
|
|
}
|
|
}
|
|
|
|
// 删除 queue 上的成员
|
|
delete(id) {
|
|
this.queue.delete(id);
|
|
}
|
|
|
|
// 暂停指定id
|
|
pause(id) {
|
|
id === undefined ? this.pauseAll() : (this.queue.get(id).paused = 1);
|
|
}
|
|
|
|
// 恢复指定id
|
|
resume(id) {
|
|
this.play(id);
|
|
}
|
|
|
|
// 播放指定id
|
|
play(id) {
|
|
id === undefined ? this.playAll() : (this.queue.get(id).paused = 0);
|
|
}
|
|
|
|
// 清空timer
|
|
clean() {
|
|
this.queue = new Map();
|
|
}
|
|
|
|
// 暂停全部 id
|
|
pauseAll() {
|
|
this.queue.forEach((item) => (item.paused = 1));
|
|
}
|
|
|
|
// 播放全部 id
|
|
playAll() {
|
|
this.queue.forEach((item) => (item.paused = 0));
|
|
}
|
|
|
|
// tick
|
|
tick(delta) {
|
|
this.paused || this.updateQueue(delta);
|
|
}
|
|
|
|
// 更新 map 队列
|
|
updateQueue(delta) {
|
|
this.queue.forEach((item, id) => {
|
|
if (item.paused === 1) return;
|
|
item.elapsed += delta;
|
|
if (item.elapsed >= item.delay) {
|
|
item.fn();
|
|
item.type === 0 ? this.delete(id) : (item.elapsed = 0);
|
|
}
|
|
});
|
|
}
|
|
|
|
// 状态更新
|
|
update() {
|
|
// 第一次调用 update 时主动停用原生接口
|
|
this.useRAF = false;
|
|
|
|
// 下面是真正的 update
|
|
this.update = (paused, delta) => {
|
|
if (this.usingRAF) return;
|
|
// 播放开关
|
|
this.paused == paused || (this.paused = paused);
|
|
this.tick(delta);
|
|
};
|
|
}
|
|
}
|
|
|
|
class AnimationFrame {
|
|
constructor() {
|
|
this.time = 0;
|
|
this.auto = this.auto.bind(this);
|
|
}
|
|
auto(elapsed) {
|
|
timer.tick(elapsed - this.time);
|
|
this.time = elapsed;
|
|
this.id = requestAnimationFrame(this.auto);
|
|
}
|
|
enable() {
|
|
timer.paused = false;
|
|
this.id = requestAnimationFrame(this.auto);
|
|
}
|
|
disable() {
|
|
cancelAnimationFrame(this.id);
|
|
}
|
|
}
|
|
|
|
// 原生RAF
|
|
Timer.RAF = new AnimationFrame();
|
|
|
|
// 对外接口
|
|
let timer = new Timer();
|
|
|
|
// 默认使用原生 RAF
|
|
timer.useRAF = true;
|
|
// 导出timer
|
|
export default timer;
|
|
|