Come differenziare un evento clic singolo e un evento doppio clic?


116

Ho un solo pulsante in li con id "my_id". Ho allegato due eventi jQuery con questo elemento

1.

$("#my_id").click(function() { 
    alert('single click');
});

2.

$("#my_id").dblclick(function() {
    alert('double click');
});

Ma ogni volta che mi dà il single click


Il singolo clic dovrà sempre scattare, è impossibile sapere se si verificherà un doppio clic a meno che non si verifichi effettivamente entro il tempo di doppio clic specificato.
Pieter Germishuys

7
Questo è possibile, controlla la mia risposta. È necessario attendere alcuni ms dopo il primo clic e verificare se è presente un nuovo clic fino all'ora specificata. In questo modo potrai sapere se si tratta di un semplice clic o di un doppio clic.
Adrien Schuler

Risposte:


65

È necessario utilizzare un timeout per verificare se è presente un altro clic dopo il primo clic.

Ecco il trucco :

// Author:  Jacek Becela
// Source:  http://gist.github.com/399624
// License: MIT

jQuery.fn.single_double_click = function(single_click_callback, double_click_callback, timeout) {
  return this.each(function(){
    var clicks = 0, self = this;
    jQuery(this).click(function(event){
      clicks++;
      if (clicks == 1) {
        setTimeout(function(){
          if(clicks == 1) {
            single_click_callback.call(self, event);
          } else {
            double_click_callback.call(self, event);
          }
          clicks = 0;
        }, timeout || 300);
      }
    });
  });
}

Uso:

$("button").single_double_click(function () {
  alert("Try double-clicking me!")
}, function () {
  alert("Double click detected, I'm hiding")
  $(this).hide()
})
<button>Click Me!</button>

MODIFICARE:

Come indicato di seguito, preferisci utilizzare l' dblclickevento nativo : http://www.quirksmode.org/dom/events/click.html

O quello fornito da jQuery: http://api.jquery.com/dblclick/


14
Questo potrebbe sembrare funzionare bene in generale, ma il tempo di ritardo consentito tra i clic (in base al quale due clic vengono interpretati come un doppio clic) differisce dalla configurazione del sistema? Probabilmente è più sicuro fare affidamento dblclicksull'evento
Jon z

1
Sì, penso che tu abbia ragione, dblclickè definitivamente la strada da percorrere oggi. jQuery gestisce anche questo evento: api.jquery.com/dblclick
Adrien Schuler

14
@AdrienSchuler - Dal documento che colleghi: non è consigliabile associare i gestori a entrambi gli eventi click e dblclick per lo stesso elemento. La domanda è avere entrambi .
Álvaro González

Quando event.detailè disponibile, è il modo migliore per rilevare un doppio clic dal gestore dei clic. Vedi questa risposta .
Carl G

Bella soluzione Adrien, ne ho bisogno per un caso in cui abbiamo un evento di clic singolo e doppio su un oggetto e solo uno dovrebbe essere attivato. Quindi la tua soluzione è perfetta per me. L'ho appena migliorato un po 'per avere "questo" sotto controllo: playcode.io/492022
LOstBrOkenKeY

79

Il comportamento dblclickdell'evento è spiegato in Quirksmode .

L'ordine degli eventi per a dblclickè:

  1. mousedown
  2. MouseUp
  3. clic
  4. mousedown
  5. MouseUp
  6. clic
  7. DblClick

L'unica eccezione a questa regola è (ovviamente) Internet Explorer con il loro ordine personalizzato di:

  1. mousedown
  2. MouseUp
  3. clic
  4. MouseUp
  5. DblClick

Come puoi vedere, l'ascolto di entrambi gli eventi insieme sullo stesso elemento comporterà chiamate extra al tuo clickgestore.


non sono sicuro dblclickneppure è affidabile ... se clicco una volta ... aspetta un secondo o due, poi clic di nuovo, dblclickal secondo clic viene visualizzato un evento!
Michael

Questi clic lunghi sono utili ad esempio per rinominare i file. Sarebbe bello se ci fossero parametri come "longClick" per distinguerlo.
PeterM

1
Quando event.detailè disponibile, è il modo migliore per rilevare un doppio clic dal gestore dei clic. Vedi questa risposta .
Carl G

38

Invece di utilizzare più stati ad-hoc e setTimeout, risulta che esiste una proprietà nativa chiamata a detailcui è possibile accedere eventdall'oggetto!

element.onclick = event => {
   if (event.detail === 1) {
     // it was a single click
   } else if (event.detail === 2) {
     // it was a double click
   }
};

I browser moderni e persino IE-9 lo supportano :)

Fonte: https://developer.mozilla.org/en-US/docs/Web/API/UIEvent/detail


La migliore risposta :)
sk8terboi87 ツ

3
In caso di doppio clic, event.detail === 1verrà comunque attivato un singolo clic (dove ). Vedi il mio violino o questo commento su questo thread .
Fabien Snauwaert

Buon punto @FabienSnauwaert. Immagino che non possiamo associare il gestore di eventi a clic singolo e doppio su un particolare elemento; il metodo sopra è utile per determinare definitivamente un doppio clic senza ricorrere a cose come il timer.
kyw

Hai ancora bisogno di un timer su quel primo clic per non sparare. Controllare la mia risposta qui sotto stackoverflow.com/questions/5497073/...

Solo una nota sull'accessibilità: se un evento clic viene attivato da una tastiera (ad esempio, quando un utente fa clic su un tasto per mettere a fuoco un pulsante e premere invio), l'evento viene generato con la proprietà di dettaglio 0, quindi facendo qualcosa come if(evt.detail !== 1) return;rifiutare il doppio accidentale i clic bloccheranno l'accesso a quel pulsante per gli utenti senza mouse.
gristow

25

Una semplice funzione. Non è richiesto alcun jquery o altro framework. Passa le tue funzioni come parametri

<div onclick="doubleclick(this, function(){alert('single')}, function(){alert('double')})">click me</div>
    <script>
        function doubleclick(el, onsingle, ondouble) {
            if (el.getAttribute("data-dblclick") == null) {
                el.setAttribute("data-dblclick", 1);
                setTimeout(function () {
                    if (el.getAttribute("data-dblclick") == 1) {
                        onsingle();
                    }
                    el.removeAttribute("data-dblclick");
                }, 300);
            } else {
                el.removeAttribute("data-dblclick");
                ondouble();
            }
        }
    </script>

2
Penso che questa dovrebbe essere la risposta migliore Tuttavia, ho dovuto ridurre il timeout a 200 perché funzionasse su Windows IE8, ma questo valore potrebbe dipendere dal sistema operativo e dall'utente. E ha anche salvato il riferimento del timer per poter annullare l'esecuzione del clic se viene registrato un doppio clic.
xpereta

Grazie per questo pezzo di codice, funziona benissimo su Chrome e Firefox (sebbene Chrome non abbia bisogno di questo hack per funzionare con dbl e single).
vincitore

usarlo el.dataset.dblclicksarebbe un modo migliore per farlo ora.
WORMSS

Quando event.detailè disponibile, è il modo migliore per rilevare un doppio clic dal gestore dei clic. Vedi questa risposta .
Carl G

12

Temo che il comportamento dipenda dal browser:

Non è consigliabile associare i gestori agli eventi click e dblclick per lo stesso elemento. La sequenza degli eventi attivati ​​varia da browser a browser, alcuni ricevono due eventi di clic prima del doppio clic e altri solo uno. La sensibilità del doppio clic (il tempo massimo tra i clic rilevato come doppio clic) può variare in base al sistema operativo e al browser ed è spesso configurabile dall'utente.

http://api.jquery.com/dblclick/

Eseguendo il codice in Firefox, alert () nel click()gestore ti impedisce di fare clic una seconda volta. Se rimuovi tale avviso, ottieni entrambi gli eventi.


Quando event.detailè disponibile, è il modo migliore per rilevare un doppio clic dal gestore dei clic. Vedi questa risposta .
Carl G

11

Bene, per fare doppio clic (fare clic due volte) devi prima fare clic una volta. Il click()gestore si attiva al primo clic e, poiché viene visualizzato l'avviso, non hai la possibilità di eseguire il secondo clic per licenziare il dblclick()gestore.

Cambia i tuoi gestori per fare qualcosa di diverso da un alert()e vedrai il comportamento. (forse cambia il colore di sfondo dell'elemento):

$("#my_id").click(function() { 
    $(this).css('backgroundColor', 'red')
});

$("#my_id").dblclick(function() {
    $(this).css('backgroundColor', 'green')
});

7

Questa risposta è diventata obsoleta nel tempo, controlla la soluzione di @ kyw.

Ho creato una soluzione ispirata all'essenza pubblicata da @AdrienSchuler. Utilizzare questa soluzione solo quando si desidera associare un singolo clic E un doppio clic a un elemento. Altrimenti consiglio di utilizzare il nativo clicke gli dblclickascoltatori.

Queste sono le differenze:

  • Vanillajs, nessuna dipendenza
  • Non aspettare setTimeoutche gestisca il gestore del clic o del doppio clic
  • Quando si fa doppio clic su di esso si attiva prima il gestore dei clic, quindi il gestore del doppio clic

Javascript:

function makeDoubleClick(doubleClickCallback, singleClickCallback) {
    var clicks = 0, timeout;
    return function() {
        clicks++;
        if (clicks == 1) {
            singleClickCallback && singleClickCallback.apply(this, arguments);
            timeout = setTimeout(function() { clicks = 0; }, 400);
        } else {
            timeout && clearTimeout(timeout);
            doubleClickCallback && doubleClickCallback.apply(this, arguments);
            clicks = 0;
        }
    };
}

Uso:

var singleClick = function(){ console.log('single click') };
var doubleClick = function(){ console.log('double click') };
element.addEventListener('click', makeDoubleClick(doubleClick, singleClick));

Di seguito è riportato l'utilizzo in un jsfiddle, il pulsante jQuery è il comportamento della risposta accettata.

jsfiddle


2
Il codice sopra e la versione 'Vanilla' del tuo violino non funzionano ... ecco una versione Vanilla fissa: jsfiddle.net/jeum/cpbwx5vr/19
jeum

@jeum Fa ancora il trucco per me in tutti i browser. Cosa "non funziona" e cosa ti aspetti? Sembra che la tua versione non stia facendo quello che volevo.
A1rPun

Per prima cosa ho modificato la mia versione (rimossa la doppia chiusura), prova la nuova: jsfiddle.net/jeum/cpbwx5vr/20 Il problema con il tuo violino (versione Vanilla) è che il doppio clic attiva il singolo gestore: recupera il singolo + doppio per me.
jeum

@jeum Quello dà un errore. Sì, la mia risposta è diversa da quella accettata e da altre risposte qui e specifico anche questa differenza in questa riga: spara un clic, quindi un doppio clic (non andare direttamente al
doppio clic

1
Sì, di nuovo errore, quindi questa versione risponde alla domanda principale: jsfiddle.net/jeum/cpbwx5vr/21 . Ora per quanto riguarda la tua versione (è vero che non avevo capito), hai notato che 'jQuery' non ottiene quello che vuoi nel tuo violino?
jeum

5

Un'altra semplice soluzione Vanilla basata sulla risposta A1rPun (guarda il suo violino per la soluzione jQuery, ed entrambi sono in questa ).

Sembra che per NON attivare un gestore a clic singolo quando l'utente fa doppio clic, il gestore a clic singolo viene necessariamente attivato dopo un ritardo ...

var single = function(e){console.log('single')},
    double = function(e){console.log('double')};

var makeDoubleClick = function(e) {

  var clicks = 0,
      timeout;

  return function (e) {

    clicks++;

    if (clicks == 1) {
      timeout = setTimeout(function () {
        single(e);
        clicks = 0;
      }, 250);
    } else {
      clearTimeout(timeout);
      double(e);
      clicks = 0;
    }
  };
}
document.getElementById('btnVanilla').addEventListener('click', makeDoubleClick(), false);

3
Questa è davvero la migliore alternativa se non vuoi che il singolo clic
venga attivato

Quando event.detailè disponibile, è il modo migliore per rilevare un doppio clic dal gestore dei clic. Vedi questa risposta .
Carl G

5

Ecco un'alternativa al codice di jeum per un numero arbitrario di eventi:

 var multiClickHandler = function (handlers, delay) {
    var clicks = 0, timeout, delay = delay || 250;
    return function (e) {
      clicks++;
      clearTimeout(timeout);
      timeout = setTimeout(function () {
        if(handlers[clicks]) handlers[clicks](e);
        clicks = 0;
      }, delay);
    };
  }

  cy.on('click', 'node', multiClickHandler({
    1: function(e){console.log('single clicked ', e.cyTarget.id())},
    2: function(e){console.log('double clicked ', e.cyTarget.id())},
    3: function(e){console.log('triple clicked ', e.cyTarget.id())},
    4: function(e){console.log('quadro clicked ', e.cyTarget.id())},
    // ...
  }, 300));

Necessario per un'app cytoscape.js .


Bello! possiamo anche dichiarare una nuova variabile all'interno della funzione restituita e assegnarla con this, che è l'elemento cliccato, e passarla al gestore (accanto eo al suo posto).
HeyJude

5

Come distinguere tra clic singoli e doppi clic su uno stesso elemento?

Se non hai bisogno di mescolarli, puoi fare affidamento su clickedblclick e ognuno farà il lavoro bene.

Quando si cerca di combinarli, sorge un problema: un dblclickevento in realtà attiverà anche un clickevento , quindi è necessario determinare se un singolo clic è un singolo clic "autonomo" o parte di un doppio clic.

Inoltre: non dovresti usare entrambi clicke dblclicksullo stesso elemento :

Non è consigliabile associare i gestori agli eventi click e dblclick per lo stesso elemento. La sequenza degli eventi attivati ​​varia da browser a browser, alcuni ricevono due eventi di clic prima del doppio clic e altri solo uno. La sensibilità del doppio clic (il tempo massimo tra i clic rilevato come doppio clic) può variare in base al sistema operativo e al browser ed è spesso configurabile dall'utente.
Fonte: https://api.jquery.com/dblclick/

Ora passiamo alla buona notizia:

È possibile utilizzare la detailproprietà dell'evento per rilevare il numero di clic relativi all'evento. Questo fa doppi clic all'interno diclick abbastanza facili da rilevare.

Resta il problema di rilevare i singoli clic e se fanno o meno parte di un doppio clic. Per questo, torniamo a utilizzare un timer e setTimeout.

Mettendo tutto insieme, con l'uso di un attributo di dati (per evitare una variabile globale) e senza la necessità di contare noi stessi i clic, otteniamo:

HTML:

<div class="clickit" style="font-size: 200%; margin: 2em; padding: 0.25em; background: orange;">Double click me</div>

<div id="log" style="background: #efefef;"></div>

JavaScript:

<script>
var clickTimeoutID;
$( document ).ready(function() {

    $( '.clickit' ).click( function( event ) {

        if ( event.originalEvent.detail === 1 ) {
            $( '#log' ).append( '(Event:) Single click event received.<br>' );

            /** Is this a true single click or it it a single click that's part of a double click?
             * The only way to find out is to wait it for either a specific amount of time or the `dblclick` event.
             **/
            clickTimeoutID = window.setTimeout(
                    function() {
                        $( '#log' ).append( 'USER BEHAVIOR: Single click detected.<br><br>' );
                    },
                    500 // how much time users have to perform the second click in a double click -- see accessibility note below.
                );

        } else if ( event.originalEvent.detail === 2 ) {
            $( '#log' ).append( '(Event:) Double click event received.<br>' );
            $( '#log' ).append( 'USER BEHAVIOR: Double click detected.<br>' );
            window.clearTimeout( clickTimeoutID ); // it's a dblclick, so cancel the single click behavior.
        } // triple, quadruple, etc. clicks are ignored.

    });

});
</script>

demo:

JSfiddle


Note sull'accessibilità e sulla velocità del doppio clic:

  • Come dice Wikipedia "Il ritardo massimo richiesto per due clic consecutivi per essere interpretati come un doppio clic non è standardizzato".
  • Nessun modo per rilevare la velocità del doppio clic del sistema nel browser.
  • Sembra che il valore predefinito sia 500 ms e l'intervallo 100-900 mm su Windows ( sorgente )
  • Pensa alle persone con disabilità che impostano, nelle impostazioni del loro sistema operativo, la velocità del doppio clic al minimo.
    • Se la velocità del doppio clic del sistema è inferiore a quella predefinita di 500 ms sopra, verranno attivati ​​entrambi i comportamenti del clic singolo e doppio.
    • O non utilizzare fare affidamento sul singolo e doppio clic combinato su uno stesso elemento.
    • Oppure: aggiungi un'impostazione nelle opzioni per avere la possibilità di aumentare il valore.

Ci è voluto un po 'per trovare una soluzione soddisfacente, spero che questo aiuti!


4

Usa l'eccellente plugin jQuery Sparkle. Il plugin ti dà la possibilità di rilevare il primo e l'ultimo clic. Puoi usarlo per distinguere tra clic e doppio clic rilevando se un altro clic è stato seguito dal primo clic.

Dai un'occhiata a http://balupton.com/sandbox/jquery-sparkle/demo/


3

Ho scritto un semplice plug-in jQuery che ti consente di utilizzare un evento "singleclick" personalizzato per differenziare un clic singolo da un doppio clic:

https://github.com/omriyariv/jquery-singleclick

$('#someDiv').on('singleclick', function(e) {
    // The event will be fired with a small delay.
    console.log('This is certainly a single-click');
}

3

La risposta corretta moderna è un mix tra la risposta accettata e la soluzione di @kyw. È necessario un timeout per impedire il primo clic singolo e il event.detailcontrollo per impedire il secondo clic.

const button = document.getElementById('button')
let timer
button.addEventListener('click', event => {
  if (event.detail === 1) {
    timer = setTimeout(() => {
      console.log('click')
    }, 200)
  }
})
button.addEventListener('dblclick', event => {
  clearTimeout(timer)
  console.log('dblclick')
})
<button id="button">Click me</button>


1

Mi piace evitare jquery (e altre librerie 90-140k) e, come notato, i browser gestiscono prima onclick, quindi ecco cosa ho fatto su un sito Web che ho creato (questo esempio copre anche l'acquisizione di una posizione su cui si è fatto clic xy locale)

clicksNow-0; //global js, owell

function notify2(e, right) {  // called from onclick= and oncontextmenu= (rc)
var x,y,xx,yy;
var ele = document.getElementById('wrap');  
    // offset fixed parent for local win x y
var xxx= ele.offsetLeft;
var yyy= ele.offsetTop;

//NScape
if (document.layers || document.getElementById&&!document.all) {
    xx= e.pageX;
    yy= e.pageY;
} else {
    xx= e.clientX;
    yy= e.clientY;
}
x=xx-xxx;
y=yy-yyy;

clicksNow++;
    // 200 (2/10ths a sec) is about a low as i seem to be able to go
setTimeout( "processClick( " + right + " , " + x + " , " + y + ")", 200);
}

function processClick(right, x, y) {
if (clicksNow==0) return; // already processed as dblclick
if (clicksNow==2) alert('dbl');
clicksNow=0;
    ... handle, etc ...
}

spero che aiuti


2
L'URL del tuo gioco non è necessario per comprendere la tua risposta. Lo rimuovo in modo che questo post non sia visto come un tentativo di spam.
Andrew Barber

1
l'unico aspetto negativo, 200 è una costante magica e può variare drasticamente dalle impostazioni del mouse dell'utente nel sistema operativo
Danubian Sailor

1

Sulla base della risposta di Adrien Schuler (grazie mille !!!), per Datatables.net e per molti usi, ecco una modifica:

Funzione

/**
 * For handle click and single click in child's objects
 * @param {any} selector Parents selector, like 'tr'
 * @param {any} single_click_callback Callback for single click
 * @param {any} double_click_callback Callback for dblclick
 * @param {any} timeout Timeout, optional, 300 by default
 */
jQuery.fn.single_double_click = function (selector, single_click_callback, double_click_callback, timeout) {
    return this.each(function () {
        let clicks = 0;
        jQuery(this).on('click', selector, function (event) {
            let self = this;
            clicks++;
            if (clicks == 1) {
                setTimeout(function () {
                    if (clicks == 1) {
                        single_click_callback.call(self, event);
                    } else {
                        double_click_callback.call(self, event);
                    }
                    clicks = 0;
                }, timeout || 300);
            }
        });
    });
}

Uso

$("#MyTableId").single_double_click('tr',
            function () {   //  Click
                let row = MyTable.row(this);
                let id = row.id();
                let data = row.data();
                console.log("Click in "+id+" "+data);
            },
            function () {   //  DBLClick
                let row = MyTable.row(this);
                let id = row.id();
                let data = row.data();
                console.log("DBLClick in "+id+" "+data);
            }
        );

0

questo ha funzionato per me -

var clicked=0;
function chkBtnClcked(evnt) {
    clicked++;
    // wait to see if dblclick
    if (clicked===1) {
        setTimeout(function() {
            clicked=0;
            .
            .
        }, 300); // test for another click within 300ms
    }
    if (clicked===2) {
        stopTimer=setInterval(function() {
            clicked=0;
            .
            .
        }, 30*1000); // refresh every 30 seconds
    }
}

usage-

<div id="cloneimages" style="position: fixed;" onclick="chkBtnClcked(evnt)"  title="Click for next pic; double-click for slide show"></div>

0

Basta pubblicare la risposta HTML nativa nel caso in cui sia necessario essere facile e HTML.

<p ondblclick="myFunction()" id = 'id'>Double-click me</p>

Questo ovviamente ha opzioni Jquery native. cioè ... $('#id').attr('ondblclick',function(){...})o, come affermato in precedenza,$('#id').dblclick(function(){...});


0

So che questo è vecchio, ma di seguito è riportato un unico esempio JS di un contatore di loop di base con un singolo timer per determinare un clic singolo vs doppio. Si spera che questo aiuti qualcuno.

var count = 0;
var ele = document.getElementById("my_id");
ele.addEventListener('click', handleSingleDoubleClick, false); 

function handleSingleDoubleClick()
{
  if(!count) setTimeout(TimerFcn, 400); // 400 ms click delay
  count += 1;
}
function TimerFcn() 
{
  if(count > 1) console.log('you double clicked!')
  else console.log('you single clicked')
  count = 0;
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.