web-dev-qa-db-ja.com

要素でonclickとondblclickの両方を使用する方法は?

Onclickおよびondblclickイベントハンドラーをアタッチする必要がある要素がページにあります。シングルクリックが発生した場合、ダブルクリックとは異なる処理を行う必要があります。私がこの仕事を始めようとしたとき、頭が回転し始めました。もちろん、ダブルクリックすると、onclickが常に発生します。だから私はこのようなタイムアウトベースの構造を使ってみました...

window.onload = function() {
  var timer;
  var el = document.getElementById('testButton');

  el.onclick = function() {
    timer = setTimeout(function() { alert('Single'); }, 150);        
  }

  el.ondblclick = function() {
    clearTimeout(timer);
    alert('Double');
  }
}

しかし、一貫性のない結果が得られました(IE8を使用)。多くの場合適切に機能しますが、「単一」のアラートが2回表示されることがあります。

これまでに誰かがこれをしたことがありますか?より効果的な方法はありますか?

25
Josh Stodola

Mattと同様に、タイムアウト値を少し増やしたときの方がはるかに良い経験をしました。また、シングルクリックが2回発火する問題を緩和するために(いずれにしても、より高いタイマーでは再現できませんでした)、シングルクリックハンドラーに次の行を追加しました。

el.onclick = function() {
    if (timer) clearTimeout(timer);
    timer = setTimeout(function() { alert('Single'); }, 250);        
}

このようにして、クリックが発生するようにすでに設定されている場合、それ自体がクリアされ、重複する「単一」アラートが回避されます。

26
Soldarnal

2つのアラートを受け取っている場合、ダブルクリックを検出するためのしきい値が小さすぎるようです。 150〜300ミリ秒に増やしてみてください。

また、clickとdblclickが呼び出される順序が保証されているかどうかはわかりません。したがって、dblclickが発生すると、firstクリックイベントはクリアされますが、2番目の「クリック」イベントの前に発生した場合、この2番目のイベントはそのまま単独で発生し、終了します。ダブルクリックイベントの発生とシングルクリックイベントの発生の両方で上昇します。

この潜在的な問題に対する2つの解決策が考えられます。

1)ダブルクリックイベントを実際に発生させる別のタイムアウトを設定します。ダブルクリックイベントが発生しようとしていることをコードにマークします。次に、2番目の「シングルクリック」イベントが発生すると、この状態をチェックして、「おっと、dblクリックが保留中なので、何もしない」と言います。

2)2番目のオプションは、クリックイベントに基づいてターゲット関数を交換することです。次のようになります。

window.onload = function() {
  var timer;
  var el = document.getElementById('testButton');

  var firing = false;
  var singleClick = function(){
    alert('Single');
  };

  var doubleClick = function(){ 
    alert('Double');
  };

  var firingFunc = singleClick;

  el.onclick = function() {
    // Detect the 2nd single click event, so we can stop it
    if(firing) 
      return;

    firing = true;
    timer = setTimeout(function() { 
       firingFunc(); 

       // Always revert back to singleClick firing function
       firingFunc = singleClick;
       firing = false;
    }, 150);

  }

  el.ondblclick = function() {
    firingFunc = doubleClick; 
    // Now, when the original timeout of your single click finishes, 
    // firingFunc will be pointing to your doubleClick handler        
  }
}

基本的にここで起こっていることは、設定した元のタイムアウトを継続させることです。常にfireingFunc()を呼び出します。変更されるのは、fireingFunc()が実際に指しているものだけです。ダブルクリックが検出されると、doubleClickに設定されます。そして、タイムアウトの期限が切れると、singleClickに常に戻ります。

2番目のシングルクリックイベントをインターセプトすることがわかっているので、そこに「発砲」変数もあります。

別の方法は、dblclickイベントを完全に無視し、シングルクリックとタイマーでそれを検出することです。

window.onload = function() {
  var timer;
  var el = document.getElementById('testButton');

  var firing = false;
  var singleClick = function(){
    alert('Single');
  };

  var doubleClick = function(){ 
    alert('Double');
  };

  var firingFunc = singleClick;

  el.onclick = function() {
    // Detect the 2nd single click event, so we can set it to doubleClick
    if(firing){
      firingFunc = doubleClick; 
      return;
    }

    firing = true;
    timer = setTimeout(function() { 
       firingFunc(); 

       // Always revert back to singleClick firing function
       firingFunc = singleClick;
       firing = false;
    }, 150);

  }
}

これはテストされていません:)

11
Matt

シンプル:

obj.onclick=function(e){
   if(obj.timerID){
          clearTimeout(obj.timerID);
          obj.timerID=null;
          console.log("double")
         }
       else{
          obj.timerID=setTimeout(function(){
                                            obj.timerID=null;
                                            console.log("single")
                                            },250)}
}//onclick
5
Oleksandr Kyrpa
,   cellclick   :   
        function(){
            setTimeout(function(){
                if (this.dblclickchk) return;
                setTimeout(function(){
                    click event......                   
                },100);
            },500);
        }

,   celldblclick    :   
        function(){
            setTimeout(function(){
                this.dblclickchk    =   true;
                setTimeout(function(){
                                          dblclick event.....
                },100);
                setTimeout(function(){
                    this.dblclickchk = false;
                },3000);
            },1);
        }
0
iamfreenoble

私は偶然にこれが機能することを発見しました(これはBing Mapsの場合です):

                 pushpin.clickTimer = -1;
                  Microsoft.Maps.Events.addHandler(pushpin, 'click', (pushpin) {
                    return function () {
                        if (pushpin.clickTimer == -1) {
                            pushpin.clickTimer = setTimeout((function (pushpin) {
                                return function () {
                                    alert('Single Clic!');
                                    pushpin.clickTimer = -1;
                                    // single click handle code here
                                }
                            }(pushpin)), 300);
                        }
                    }
                }(pushpin)));
                Microsoft.Maps.Events.addHandler(pushpin, 'dblclick', (function (pushpin) {
                    return function () {
                        alert('Double Click!');
                        clearTimeout(pushpin.clickTimer);
                        pushpin.clickTimer = -1;
                        // double click handle here
                    }
                }(pushpin)));

これは、クリックイベントがdblclickイベントをマスクするように見えます。この使用法により、タイムアウトを追加するとイベントがクリアされます。ですから、うまくいけば、これはBing Maps以外のケースでも機能しますが、少し調整した後で試してみませんでした。

0
user2907498

小さな修正

       if(typeof dbtimer != "undefined"){
            dbclearTimeout(timer);
            timer = undefined;
            //double click
        }else{
            dbtimer = setTimeout(function() { 
            dbtimer = undefined;
            //single click
            }, 250);
        }
0