29

マウスを押してから 放すまでのミリ秒数を測定する方法はありますか?

4

6 に答える 6

30

2 つの変数を共有するクロージャを作成できます。1 つは開始時刻を格納し、もう 1 つは終了時刻を格納し、次に 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;dr 回答と例

  • .timeStamp2 番目のイベントのプロパティから最初のイベントのプロパティを減算して、2 つのイベント間の時間を取得し.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 の回答で提案されているアプローチ (を作成し、これらの時間を互いに減算することによって各ハンドラー内の時間を取得するnew Date()) は、非常に不正確になる可能性があります。このアプローチの問題は、イベントが発生した時間を比較しているのではなく、ハンドラーが起動した時間を比較していることです。

質問者がリンクしている記事 - John Resig のHow JavaScript Timers Work - は、ここでの問題を理解するのに関連しています。JavaScript の実行はシングル スレッドであり、タイムアウトの起動、イベントの発生、スクリプトの読み込みなど、JavaScript の外部の何かが JavaScript の実行をトリガーするたびに、その JavaScript は起動を待機しているコールバックのキューに追加され、順番に実行されます。

これにより、イベント間の時間を計算しようとすると、ハンドラーの実行時間に基づいて計算しようとすると、いくつかの方法でひどく失敗する可能性があります。次の 2 つのシナリオを検討してください。

最初のシナリオ
  1. 計算コストの高い JavaScript の実行が開始され、実行に 1 秒かかります。
  2. 最初のイベントが発生します (つまり、ユーザーがターゲット要素にマウスを置いたとき)
  3. 200 ミリ秒後、2 番目のイベントが発生します (つまり、ユーザーがターゲット要素にマウスを合わせます)。

次は何が起こる?計算コストの高い JavaScript の実行が終了すると、両方のイベント ハンドラーが立て続けに起動します。したがって、ハンドラーが起動する現在の時刻を取得してイベントのタイミングを計っている場合、イベント間の時間が 0 ミリ秒近くになると誤って計算されます。

2 番目のシナリオ
  1. 最初のイベントが発生し、そのハンドラが起動します。後で参照できるように現在の時刻を変数に格納し、完了までに 1 秒かかる計算を開始します。
  2. 最初のイベントがトリガーされてから 200 ミリ秒後に、2 番目のイベントがトリガーされます。

次は何が起こる?今回はもちろん、2 番目のハンドラーの実行が遅れるため、イベント間の時間を約 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>

ボタンをクリックするだけで、マウスダウンとマウスアップの間の計算された時間差が常に約 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

少なくともクロムでは、他のリンクが壊れているように見えるので、簡単な動作デモを次に示します。

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

2 つのグローバル変数を使用して、マウスダウンとマウスアップの時間を記録し、減算を行うことができます。

于 2009-09-01T06:27:21.570 に答える