29

有没有办法测量鼠标按下释放之间的毫秒数?

4

6 回答 6

30

您可以创建一个闭包来共享两个变量,一个用于存储开始时间,另一个用于存储结束时间,然后在 mouseup 事件中获取差异:

(function () {
    var element = document.getElementById('element'),
        start, end;

    element.onmousedown = function () {
      start = +new Date(); // get unix-timestamp in milliseconds
    };


    element.onmouseup = function () {
      end = +new Date();

      var diff = end - start; // time difference in milliseconds
    };

})();

检查这个工作示例

于 2009-09-01T06:28:03.753 回答
20

tl;博士答案和例子

  • 通过从第二个事件的属性中减去.timeStamp第一个事件的属性来获取两个事件之间的时间.timeStamp
  • 永远不要试图通过在其处理程序中创建new Date()或调用来获取事件发生的时间。Date.now()
  • 请注意,即使您遵循此建议,在某些浏览器的版本中,如果您的事件处理程序的执行由于某些不相关的 JavaScript 的缓慢执行而延迟,您也会得到错误的结果。

const button = document.getElementById("button");
let mousedownTime;

button.addEventListener('mousedown', () => {
  mousedownTime = new Date().getTime();
});

button.addEventListener('mouseup', function () {
  const mouseupTime = new Date().getTime(),
        timeDifference = mouseupTime - mousedownTime;
  alert(`Button held down for ${timeDifference}ms`);
});
<button id="button">Click Me</button>

更长的答案和解释

这是一个比这里的其他答案更微妙的问题。

CMS 的回答提出的方法- 通过创建 anew Date()然后将这些时间相互减去来获取每个处理程序内部的时间 - 有可能非常不准确。这种方法的问题在于,您不是在比较事件发生的时间,而是在比较它们的处理程序触发的时间。

提问者链接到的文章——John Resig 的JavaScript 定时器如何工作——与理解这里的问题有关。JavaScript 执行是单线程的,每当 JavaScript 之外的东西触发一些 JavaScript 执行时——无论是超时触发、事件发生还是脚本加载——JavaScript 都会被添加到等待触发的回调队列中,这些回调队列会按顺序执行。

如果我们尝试根据处理程序运行的时间来计算它,这导致我们尝试计算事件之间的时间的几种方式可能会变得非常糟糕。考虑以下两种情况:

第一种情况
  1. 一些计算量大的 JavaScript 开始执行,需要 1 秒才能执行。
  2. 第一个事件发生(即用户将鼠标放在目标元素上)
  3. 200 毫秒后,第二个事件发生(即用户将鼠标移到目标元素上)。

接下来发生什么?计算量大的 JavaScript 完成运行,然后两个事件处理程序快速连续触发。因此,如果您通过获取处理程序触发的当前时间来计时事件,您将错误地计算事件之间的时间接近 0 毫秒。

第二种情况
  1. 第一个事件发生并触发其处理程序。它将当前时间存储在一个变量中以供以后参考,然后开始进行一些需要 1 秒才能完成的计算。
  2. 触发第一个事件后 200 毫秒,触发第二个事件。

接下来发生什么?这一次,当然,我们会错误地将事件之间的时间计算为大约 1 秒,因为第二个处理程序的执行被延迟了。

你可以在这里看到这个:

const button = document.getElementById("button");
let mousedownTime;

button.addEventListener('mousedown', function () {
  mousedownTime = new Date().getTime();
  document.getElementById("mousedown-time").innerHTML = mousedownTime;
  document.getElementById("time-difference").innerHTML = '';
  hotSleep();
});

button.addEventListener('mouseup', function () {
  const mouseupTime = new Date().getTime(),
        timeDifference = mouseupTime - mousedownTime;
  document.getElementById("mouseup-time").innerHTML = mouseupTime;
  document.getElementById("time-difference").innerHTML = timeDifference;
});

/**
 * Hot-sleeps for 1 second when called.
 * 
 * In a real life scenario, this might be some expensive numerical
 * computation, or some DOM manipulation code.
 */
function hotSleep () {
  const startTime = new Date().getTime();
  while (new Date().getTime() < startTime+1000) {}
}
<button id="button">Click Me</button>
<div>
  Time of last mousedown: <span id="mousedown-time"></span>
</div>
<div>
  Time of last mouseup: <span id="mouseup-time"></span>
</div>
<div>
  Time between events: <span id="time-difference"></span>
</div>

只需单击按钮,观察计算出来的 mousedown 和 mouseup 之间的时间差总是大约 1000 毫秒。

我们能做些什么来阻止这种情况?好吧,理想情况下,我们想要一种方法来获取事件发生的实际时间,不仅仅是其处理程序触发的时间。DOM API 是否为我们提供了这样的东西?

在现代浏览器中,是的。事件有一个.timeStamp属性,现在它应该提供事件发生的时间,而不是处理程序触发的时间。(过去不是这样;当我第一次写这个答案时,只有 Firefox 正确地实现了这个,其他浏览器会返回处理程序触发的时间。谢天谢地,现在每个人都正确地实现了这个。)

那么,下面是该示例的修改版本,上面带有热睡眠。唯一的变化是事件发生的时间是使用事件的.timestamp属性确定的——这足以意味着我们现在可以正确计算点击的持续时间。

const button = document.getElementById("button");
let mousedownTime;

button.addEventListener('mousedown', e => {
  mousedownTime = e.timeStamp;
  document.getElementById("mousedown-time").innerHTML = mousedownTime;
  document.getElementById("time-difference").innerHTML = '';
  hotSleep();
});

button.addEventListener('mouseup', e => {
  const mouseupTime = e.timeStamp,
        timeDifference = mouseupTime - mousedownTime;
  document.getElementById("mouseup-time").innerHTML = mouseupTime;
  document.getElementById("time-difference").innerHTML = timeDifference;
});

/**
 * Hot-sleeps for 1 second when called.
 * 
 * In a real life scenario, this might be some expensive numerical
 * computation, or some DOM manipulation code.
 */
function hotSleep () {
  const startTime = new Date().getTime();
  while (new Date().getTime() < startTime+1000) {}
}
<button id="button">Click Me</button>
<div>
  Time of last mousedown: <span id="mousedown-time"></span>
</div>
<div>
  Time of last mouseup: <span id="mouseup-time"></span>
</div>
<div>
  Time between events: <span id="time-difference"></span>
</div>

于 2014-12-16T22:28:12.580 回答
5

由于其他链接现在似乎被破坏了,至少在 chrome 上,这是一个简单的工作演示:

var startTime;

window.startTimer = function() {
    startTime = new Date();
}
window.reportTime = function() {
	alert(new Date() - startTime)
}
<button onmousedown="startTimer()" onmouseup="reportTime()">Measure click time</button>

于 2016-06-05T03:20:06.623 回答
4

当 onmousedown 被触发时,您可以在窗口上挂起 onmouseup 事件。这将允许避免不必要的关闭。

el.onmousedown = function () {
  var time = new Date(); //time in milliseconds
  window.onmouseup=function(){
    var diff=new Date()-time;
    window.onmouseup=null;
  }
};

在这里查看结果:http: //jsbin.com/uneqo

于 2009-09-01T06:43:47.700 回答
0

可以使用两个全局变量来记录mousedown和mouseup的时间,并有一个减法

于 2009-09-01T06:27:21.570 回答
0

我认为这是最优雅的方式:

 function onMouseDown(e) {
    window.onmouseup = function(e2) {
      var diff = e2.timeStamp - e.originalEvent.timeStamp;
      console.log(diff);
      window.onmouseup = null;
    };
  }
于 2020-12-20T17:56:52.903 回答