这里是一个示例代码,显示即使进行简单的单击,mouseUp 和 mouseDown 也会产生 2 个不同的动画帧。
const d = document.createElement('div');
const b = document.createElement('button');
b.textContent = 'Click me!';
b.addEventListener('mousedown', (e) => {
schedule(() => console.log('schedule button mousedown'));
console.log('button mousedown');
});
b.addEventListener('click', () => {
schedule(() => console.log('schedule button click'));
console.log('button click');
});
b.addEventListener('mouseup', () => {
schedule(() => console.log('schedule button mouseup'));
console.log('button mouseup');
});
document.body.appendChild(d);
d.appendChild(b);
let timerId;
function schedule(cb) {
if (timerId === undefined) {
timerId = requestAnimationFrame(() => {
console.log('running synchronization');
timerId = undefined;
});
}
}
它记录:
button mousedown
running synchronization
button mouseup
button click
running synchronization
有人可以给我一个“权威答案”来解释为什么他们系统地安排不同的帧,即使事件不是长时间的点击。 (这在长点击上下文中是有意义的)。
然后我们就可以作弊了。
requestAnimationFrame
并不完全与显示器的刷新率相关,如果我们锁定事件循环足够长的时间,我们就可以让两个事件在同一动画帧中排队。
在下面的代码片段中,我们显示了两个事件之间经过的帧数,并且我们允许将事件循环锁定 300 毫秒,以表明在这些事件之间不会强制触发新的动画帧。
const locker = document.querySelector("input");
const b = document.querySelector("button");
b.addEventListener('mousedown', (e) => {
schedule(() => console.log('schedule button mousedown'));
if (locker.checked) {
const t1 = performance.now();
while (performance.now() - t1 < 300) {}
}
console.log('button mousedown');
});
b.addEventListener('click', () => {
schedule(() => console.log('schedule button click'));
console.log('button click');
});
b.addEventListener('mouseup', () => {
schedule(() => console.log('schedule button mouseup'));
console.log('button mouseup');
console.log("frames elapsed: ", count);
running = false;
count = 0;
});
let running = false;
let timerId;
let count = 0;
function schedule(cb) {
if (timerId === undefined) {
running = true;
timerId = requestAnimationFrame(() => {
console.log('running synchronization');
timerId = undefined;
});
}
}
// An ever running animation loop that increments our counter
// when the running flag is on
const anim = () => {
if (running) {
count++;
}
requestAnimationFrame(anim);
};
anim();
<label>Lock event loop in mousedown <input type=checkbox></label><br>
<button>click me</button>
Ps:在触摸设备上运行此代码片段,即使没有锁定事件循环,计数也可能为零。