为什么 mouseDown 和 mouseUp 事件不调度相同的animationFrame?

问题描述 投票:0回答:1

这里是一个示例代码,显示即使进行简单的单击,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;
    });
  }
}

Stackblitz 演示

它记录:

button mousedown
running synchronization
button mouseup
button click
running synchronization

有人可以给我一个“权威答案”来解释为什么他们系统地安排不同的帧,即使事件不是长时间的点击。 (这在长点击上下文中是有意义的)。

javascript typescript requestanimationframe
1个回答
0
投票

然后我们就可以作弊了。

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:在触摸设备上运行此代码片段,即使没有锁定事件循环,计数也可能为零。

© www.soinside.com 2019 - 2024. All rights reserved.