Comment différencier un événement simple clic et un événement double clic?

116

J'ai un seul bouton en li avec id "my_id". J'ai attaché deux événements jQuery avec cet élément

1.

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

2.

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

Mais à chaque fois, ça me donne le single click

user426795
la source
Le simple clic devra toujours se déclencher, il est impossible de savoir si un double clic va se produire à moins qu'il ne se produise réellement dans le temps de double clic spécifié.
Pieter Germishuys
7
C'est possible, vérifiez ma réponse. Vous devez attendre quelques ms après le premier clic et vérifier s'il y a un nouveau clic jusqu'à l'heure spécifiée. De cette façon, vous êtes en mesure de savoir s'il ne s'agit que d'un simple ou d'un double clic.
Adrien Schuler

Réponses:

65

Vous devez utiliser un délai d'attente pour vérifier s'il y a un autre clic après le premier clic.

Voici l'astuce :

// 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);
      }
    });
  });
}

Usage:

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

ÉDITER:

Comme indiqué ci-dessous, préférez utiliser l' dblclickévénement natif : http://www.quirksmode.org/dom/events/click.html

Ou celui fourni par jQuery: http://api.jquery.com/dblclick/

Adrien Schuler
la source
14
Cela peut sembler fonctionner correctement en général, mais le temps de latence autorisé entre les clics (par lequel deux clics sont interprétés comme un double-clic) ne diffère-t-il pas selon la configuration du système? Il est probablement plus sûr de se fier à l' dblclickévénement
Jon z
1
Ouais je pense que tu as raison, dblclickc'est définitivement la voie à suivre aujourd'hui. jQuery gère également cet événement: api.jquery.com/dblclick
Adrien Schuler
14
@AdrienSchuler - Depuis la doc que vous liez: Il est déconseillé de lier les gestionnaires aux événements click et dblclick pour le même élément. La question est d'avoir les deux .
Álvaro González
Lorsqu'elle event.detailest disponible, c'est le meilleur moyen de détecter un double-clic du gestionnaire de clics. Voyez cette réponse .
Carl G
Belle solution Adrien, j'en ai besoin pour un cas où nous avons un événement simple et double clic sur un objet et un seul devrait être déclenché. Par conséquent, votre solution est parfaite pour moi. Je viens de l'améliorer un peu pour avoir "ceci" sous contrôle: playcode.io/492022
LOstBrOkenKeY
79

Le comportement de l' dblclickévénement est expliqué dans Quirksmode .

L'ordre des événements pour a dblclickest:

  1. souris vers le bas
  2. souris
  3. Cliquez sur
  4. souris vers le bas
  5. souris
  6. Cliquez sur
  7. dblclick

La seule exception à cette règle est (bien sûr) Internet Explorer avec son ordre personnalisé de:

  1. souris vers le bas
  2. souris
  3. Cliquez sur
  4. souris
  5. dblclick

Comme vous pouvez le voir, écouter les deux événements ensemble sur le même élément entraînera des appels supplémentaires à votre clickgestionnaire.

Ryan
la source
pas sûr dblclickest même fiable ... si je clique une fois ... attendez une seconde ou deux, puis cliquez à nouveau, j'obtiens un dblclickévénement sur le deuxième clic!
Michael
Ces longs clics sont utiles par exemple pour renommer des fichiers. Ce serait bien s'il y avait un paramètre comme «longClick» pour le distinguer.
PeterM
1
Lorsqu'elle event.detailest disponible, c'est le meilleur moyen de détecter un double-clic du gestionnaire de clics. Voyez cette réponse .
Carl G
38

Au lieu d'utiliser plus d'états ad hoc et setTimeout, il s'avère qu'il existe une propriété native appelée à detaillaquelle vous pouvez accéder à partir de l' eventobjet!

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

Les navigateurs modernes et même IE-9 le prennent en charge :)

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

kyw
la source
La meilleure réponse :)
sk8terboi87 ツ
3
En cas de double clic, un simple clic (où event.detail === 1) se déclenchera toujours. Voir mon violon ou ce commentaire sur ce fil .
Fabien Snauwaert
Bon point @FabienSnauwaert. Je suppose que nous ne pouvons pas lier à la fois le gestionnaire d'événements simple et double clic sur un élément particulier; la méthode ci-dessus est utile pour déterminer définitivement un double clic sans recourir à des trucs comme le minuteur.
kyw
Vous avez toujours besoin d'une minuterie sur ce premier clic pour ne pas tirer. Vérifiez ma réponse ci-dessous stackoverflow.com/questions/5497073
Juste une note d'accessibilité: si un événement de clic est déclenché par un clavier (par exemple, lorsqu'un utilisateur tabule pour focaliser un bouton et appuyez sur Entrée), l'événement est généré avec la propriété detail à 0, donc faire quelque chose comme if(evt.detail !== 1) return;rejeter un double accidentel les clics bloqueront l'accès à ce bouton pour les utilisateurs sans souris.
gristow
25

Une fonction simple. Aucun jquery ou autre framework n'est requis. Passez vos fonctions en paramètres

<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>
Renzo Ciot
la source
2
Je pense que cela devrait être la meilleure réponse, mais j'ai dû réduire le délai à 200 pour que cela fonctionne sur Windows IE8, mais cette valeur peut dépendre du système d'exploitation et de l'utilisateur. Et a également enregistré la référence de la minuterie pour pouvoir annuler l'exécution du clic si un double clic est enregistré.
xpereta
Merci pour ce morceau de code, il fonctionne très bien sur chrome et firefox (bien que chrome n'ait pas besoin de ce hack pour fonctionner avec dbl et single).
victor
utiliser el.dataset.dblclickserait une meilleure façon de le faire maintenant.
WORMSS
Lorsqu'elle event.detailest disponible, c'est le meilleur moyen de détecter un double-clic du gestionnaire de clics. Voyez cette réponse .
Carl G
12

J'ai peur que le comportement dépende du navigateur:

Il est déconseillé de lier les gestionnaires aux événements click et dblclick pour le même élément. La séquence des événements déclenchés varie d'un navigateur à l'autre, certains recevant deux événements de clic avant le dblclick et d'autres un seul. La sensibilité du double-clic (temps maximum entre les clics détecté comme un double-clic) peut varier selon le système d'exploitation et le navigateur, et est souvent configurable par l'utilisateur.

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

En exécutant votre code dans Firefox, l'alerte () dans le click()gestionnaire vous empêche de cliquer une seconde fois. Si vous supprimez cette alerte, vous obtenez les deux événements.

Álvaro González
la source
Lorsqu'elle event.detailest disponible, c'est le meilleur moyen de détecter un double-clic du gestionnaire de clics. Voyez cette réponse .
Carl G
11

Eh bien, pour double-cliquer (cliquez deux fois), vous devez d'abord cliquer une fois. Le click()gestionnaire se déclenche lors de votre premier clic, et puisque l'alerte apparaît, vous n'avez aucune chance de faire le deuxième clic pour déclencher le dblclick()gestionnaire.

Changez vos gestionnaires pour faire autre chose qu'un alert()et vous verrez le comportement. (peut-être changer la couleur d'arrière-plan de l'élément):

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

$("#my_id").dblclick(function() {
    $(this).css('backgroundColor', 'green')
});
bradley.ayers
la source
7

Cette réponse est devenue obsolète avec le temps, consultez la solution de @ kyw.

J'ai créé une solution inspirée de l'essentiel publié par @AdrienSchuler. Utilisez cette solution uniquement lorsque vous souhaitez lier un simple clic ET un double-clic à un élément. Sinon, je recommande d'utiliser le natif clicket les dblclickauditeurs.

Voici les différences:

  • Vanillajs, pas de dépendances
  • N'attendez pas setTimeoutpour gérer le gestionnaire de clic ou de double-clic
  • Lorsque vous double-cliquez dessus, vous déclenchez d'abord le gestionnaire de clic, puis le gestionnaire de double-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;
        }
    };
}

Usage:

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

Voici l'utilisation dans un jsfiddle, le bouton jQuery est le comportement de la réponse acceptée.

jsfiddle

A1rPun
la source
2
Le code ci-dessus et la version 'Vanilla' de votre violon ne fonctionnent pas ... voici une version Vanilla corrigée
jeum
@jeum Cela fait toujours l'affaire pour moi dans tous les navigateurs. Qu'est-ce que «ne fonctionne pas» et à quoi vous attendez-vous? Il semble que votre version ne fasse pas ce que je voulais.
A1rPun
J'ai d'abord modifié ma version (suppression de la double fermeture), veuillez essayer la nouvelle: jsfiddle.net/jeum/cpbwx5vr/20 Le problème avec votre violon (version Vanilla) est que le double-clic déclenche le gestionnaire simple: il récupère le simple + double pour moi.
jeum
@jeum Celui-là donne une erreur. Oui, ma réponse diffère des réponses acceptées et des autres réponses ici et je précise également cette différence dans cette ligne: Tirez un clic, puis un double-clic (ne passez pas directement au double-clic)
A1rPun
1
Oui, encore une fois, cette version répond à la question principale: jsfiddle.net/jeum/cpbwx5vr/21 . Maintenant concernant votre version (c'est vrai que je n'avais pas compris), avez-vous remarqué que 'jQuery' n'atteint pas ce que vous voulez dans votre violon?
jeum
5

Une autre solution Vanilla simple basée sur la réponse A1rPun (voir son violon pour la solution jQuery, et les deux sont dans celle-ci ).

Il semble que pour NE PAS déclencher un gestionnaire en un seul clic lorsque l'utilisateur double-clique, le gestionnaire en un seul clic est forcément déclenché après un délai ...

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);
jeum
la source
3
C'est en effet la meilleure alternative si vous ne voulez pas que le simple clic soit déclenché :)
A1rPun
Lorsqu'elle event.detailest disponible, c'est le meilleur moyen de détecter un double-clic du gestionnaire de clics. Voyez cette réponse .
Carl G
5

Voici une alternative au code de jeum pour un nombre arbitraire d'événements:

 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));

J'en ai besoin pour une application cytoscape.js .

nex
la source
Agréable! nous pouvons également déclarer une nouvelle variable à l'intérieur de la fonction retournée et l'affecter avec this, qui est l'élément cliqué, et la passer au gestionnaire (à côté eou à sa place).
HeyJude
5

Comment différencier les simples clics et les doubles clics sur un seul et même élément?

Si vous n'avez pas besoin de les mélanger, vous pouvez compter sur clicket dblclickchacun fera le travail très bien.

Un problème survient lorsque vous essayez de les mélanger: un dblclickévénement déclenchera également un clickévénement , vous devez donc déterminer si un simple clic est un simple clic "autonome" ou une partie d'un double clic.

De plus: vous ne devez pas utiliser les deux clicket dblclicksur un seul et même élément :

Il est déconseillé de lier les gestionnaires aux événements click et dblclick pour le même élément. La séquence des événements déclenchés varie d'un navigateur à l'autre, certains recevant deux événements de clic avant le dblclick et d'autres un seul. La sensibilité du double-clic (temps maximum entre les clics détecté comme un double-clic) peut varier selon le système d'exploitation et le navigateur, et est souvent configurable par l'utilisateur.
Source: https://api.jquery.com/dblclick/

Passons maintenant aux bonnes nouvelles:

Vous pouvez utiliser la detailpropriété de l'événement pour détecter le nombre de clics liés à l'événement. Cela rend les doubles clics à l'intérieur clickassez faciles à détecter.

Le problème demeure de détecter les clics simples et s'ils font ou non partie d'un double clic. Pour cela, nous revenons à l'utilisation d'une minuterie et setTimeout.

Enveloppant le tout ensemble, avec l'utilisation d'un attribut de données (pour éviter une variable globale) et sans avoir besoin de compter les clics nous-mêmes, nous obtenons:

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>

Démo:

JSfiddle


Remarques sur l'accessibilité et les vitesses de double-clic:

  • Comme le dit Wikipedia "Le délai maximum requis pour que deux clics consécutifs soient interprétés comme un double-clic n'est pas normalisé."
  • Aucun moyen de détecter la vitesse du double-clic du système dans le navigateur.
  • Semble que la valeur par défaut est de 500 ms et la plage de 100 à 900 mm sous Windows ( source )
  • Pensez aux personnes handicapées qui définissent, dans leurs paramètres de système d'exploitation, la vitesse du double-clic la plus lente.
    • Si la vitesse du double-clic du système est plus lente que notre valeur par défaut de 500 ms ci-dessus, les comportements de simple et double-clic seront déclenchés.
    • Soit n'utilisez pas la combinaison d'un simple et d'un double clic sur un seul et même élément.
    • Ou: ajoutez un paramètre dans les options pour avoir la possibilité d'augmenter la valeur.

Il a fallu du temps pour trouver une solution satisfaisante, j'espère que cela vous aidera!

Fabien Snauwaert
la source
4

Utilisez l'excellent plugin jQuery Sparkle. Le plugin vous donne la possibilité de détecter le premier et le dernier clic. Vous pouvez l'utiliser pour différencier click et dblclick en détectant si un autre clic a été suivi du premier clic.

Découvrez-le sur http://balupton.com/sandbox/jquery-sparkle/demo/

Hussein
la source
3

J'ai écrit un simple plugin jQuery qui vous permet d'utiliser un événement personnalisé 'singleclick' pour différencier un simple clic d'un double-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');
}
omriyariv
la source
3

La bonne réponse moderne est un mélange entre la réponse acceptée et la solution de @kyw. Vous avez besoin d'un délai pour empêcher ce premier clic simple et de la event.detailvérification pour empêcher le deuxième 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>


la source
1

J'aime éviter jquery (et d'autres bibliothèques 90-140k), et comme les navigateurs notés gèrent en premier le clic, voici ce que j'ai fait sur un site Web que j'ai créé (cet exemple couvre également l'obtention d'un emplacement cliqué xy local)

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 ...
}

J'espère que cela pourra aider

Dakar
la source
2
L'URL de votre jeu n'est pas du tout nécessaire pour comprendre votre réponse. Je le supprime afin que ce message ne soit pas considéré comme une tentative de spam.
Andrew Barber
1
le seul inconvénient, 200 est une constante magique et peut varier considérablement des paramètres de la souris de l'utilisateur dans le système d'exploitation
Danubian Sailor
1

Basé sur la réponse d' Adrien Schuler (merci beaucoup !!!), pour Datatables.net et pour de nombreuses utilisations, voici une modification:

Fonction

/**
 * 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);
            }
        });
    });
}

Utilisation

$("#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);
            }
        );
Dani
la source
0

cela a fonctionné pour moi -

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>
a besoin
la source
0

Il suffit de publier la réponse HTML native au cas où le besoin serait d'être simple et HTML.

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

Ceci a bien sûr des options natives Jquery. c'est-à-dire ... $('#id').attr('ondblclick',function(){...})ou, comme indiqué précédemment,$('#id').dblclick(function(){...});

JSG
la source
0

Je sais que c'est vieux, mais ci-dessous est un seul exemple JS d'un compteur de boucle de base avec une seule minuterie pour déterminer un simple vs double clic. Espérons que cela aide quelqu'un.

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;
}
Tim Moses
la source