¿Cómo diferenciar el evento de un solo clic y el evento de doble clic?

116

Tengo un solo botón en li con id "my_id". Adjunté dos eventos jQuery con este elemento

1.

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

2.

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

Pero cada vez que me da la single click

user426795
fuente
El clic único siempre tendrá que dispararse, es imposible saber si se producirá un doble clic a menos que realmente ocurra dentro del tiempo de doble clic especificado.
Pieter Germishuys
7
Esto es posible, verifique mi respuesta. Debe esperar unos ms después del primer clic y comprobar si hay un nuevo clic hasta el tiempo especificado. De esa manera, puede saber si esto es solo un simple o un doble clic.
Adrien Schuler

Respuestas:

65

Debe utilizar un tiempo de espera para comprobar si hay otro clic después del primer clic.

Aquí está el truco :

// 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>

EDITAR:

Como se indica a continuación, prefiera usar el dblclickevento nativo : http://www.quirksmode.org/dom/events/click.html

O el proporcionado por jQuery: http://api.jquery.com/dblclick/

Adrien Schuler
fuente
14
Esto puede parecer que funciona bien en general, pero ¿no difiere el tiempo de retraso permitido entre los clics (por el cual dos clics se interpretan como un doble clic) según la configuración del sistema? Probablemente sea más seguro confiar en el dblclickevento
Jon z
1
Sí, creo que tienes razón, dblclickdefinitivamente es el camino a seguir hoy. jQuery también maneja este evento: api.jquery.com/dblclick
Adrien Schuler
14
@AdrienSchuler: desde el documento que vincula: no es aconsejable vincular controladores a los eventos click y dblclick para el mismo elemento. La pregunta se trata de tener ambos .
Álvaro González
Cuando event.detailestá disponible, es la mejor manera de detectar un doble clic desde el controlador de clics. Vea esta respuesta .
Carl G
Buena solución Adrien, la necesito para un caso en el que tengamos un evento de clic único y doble en un objeto y solo uno debería ser disparado. Por eso tu solución es perfecta para mí. Lo mejoré un poco para tener "esto" bajo control: playcode.io/492022
LOstBrOkenKeY
79

El comportamiento del dblclickevento se explica en Quirksmode .

El orden de los eventos para a dblclickes:

  1. ratón hacia abajo
  2. mouseup
  3. hacer clic
  4. ratón hacia abajo
  5. mouseup
  6. hacer clic
  7. doble clic

La única excepción a esta regla es (por supuesto) Internet Explorer con su orden personalizado de:

  1. ratón hacia abajo
  2. mouseup
  3. hacer clic
  4. mouseup
  5. doble clic

Como puede ver, escuchar ambos eventos juntos en el mismo elemento resultará en llamadas adicionales a su clickcontrolador.

Ryan
fuente
no estoy seguro si dblclickes confiable ... si hago clic una vez ... espere un segundo o dos, luego haga clic de nuevo, ¡obtengo un dblclickevento en el segundo clic!
Michael
Estos clics prolongados son útiles, por ejemplo, para cambiar el nombre de archivos. Sería bueno si hubiera un parámetro como 'longClick' para distinguirlo.
PeterM
1
Cuando event.detailestá disponible, es la mejor manera de detectar un doble clic desde el controlador de clics. Vea esta respuesta .
Carl G
38

En lugar de utilizar más estados ad-hoc y setTimeout, resulta que hay una propiedad nativa llamada a la detailque puede acceder desde el eventobjeto.

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

Los navegadores modernos e incluso IE-9 lo admiten :)

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

kyw
fuente
La mejor respuesta :)
sk8terboi87 ツ
3
En el caso de los clics dobles, event.detail === 1se activará un solo clic (donde ). Vea mi violín o este comentario en este hilo .
Fabien Snauwaert
Buen punto @FabienSnauwaert. Supongo que no podemos vincular el controlador de eventos de un solo clic y de doble clic en un elemento en particular; el método anterior es útil para determinar definitivamente un doble clic sin recurrir a cosas como el temporizador.
kyw
Aún necesita un temporizador en ese primer clic para no disparar. Verifique mi respuesta a continuación stackoverflow.com/questions/5497073/…
Solo una nota de accesibilidad: si un evento de clic es disparado por un teclado (por ejemplo, cuando un usuario presiona un botón para enfocar un botón y presionar enter), el evento se genera con la propiedad de detalle como 0, por lo que hacer algo como if(evt.detail !== 1) return;rechazar el doble accidental los clics bloquearán el acceso a ese botón para los usuarios sin un mouse.
Gristow
25

Una función sencilla. No se requiere jquery u otro marco. Pasa tus funciones como parámetros

<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
fuente
2
Creo que esta debería ser la mejor respuesta. Sin embargo, tuve que reducir el tiempo de espera a 200 para que funcione en Windows IE8, pero este valor puede depender del sistema operativo y del usuario. Y también se guardó la referencia del temporizador para poder cancelar la ejecución del clic si se registra un doble clic.
xpereta
Gracias por este código, funciona muy bien en Chrome y Firefox (aunque Chrome no necesita este truco para funcionar con dbl y single).
vencedor
usar el.dataset.dblclicksería una forma más agradable de hacer esto ahora.
WORMSS
Cuando event.detailestá disponible, es la mejor manera de detectar un doble clic desde el controlador de clics. Vea esta respuesta .
Carl G
12

Me temo que el comportamiento depende del navegador:

No es aconsejable vincular controladores a los eventos click y dblclick para el mismo elemento. La secuencia de eventos desencadenados varía de un navegador a otro, algunos reciben dos eventos de clic antes del dblclick y otros solo uno. La sensibilidad del doble clic (tiempo máximo entre los clics que se detecta como un doble clic) puede variar según el sistema operativo y el navegador, y a menudo es configurable por el usuario.

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

Al ejecutar su código en Firefox, la alerta () en el click()controlador le impide hacer clic por segunda vez. Si elimina dicha alerta, obtendrá ambos eventos.

Álvaro González
fuente
Cuando event.detailestá disponible, es la mejor manera de detectar un doble clic desde el controlador de clics. Vea esta respuesta .
Carl G
11

Bueno, para hacer doble clic (hacer clic dos veces) primero debe hacer clic una vez. El click()controlador dispara en su primer clic y, dado que aparece la alerta, no tiene la oportunidad de hacer el segundo clic para disparar al dblclick()controlador.

Cambie sus manejadores para hacer algo diferente a un alert()y verá el comportamiento. (quizás cambie el color de fondo del elemento):

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

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

Esta respuesta se ha vuelto obsoleta con el tiempo, verifique la solución de @ kyw.

Creé una solución inspirada en la esencia publicada por @AdrienSchuler. Utilice esta solución solo cuando desee vincular un solo clic Y un doble clic a un elemento. De lo contrario, recomiendo usar el nativo clicky los dblclickoyentes.

Estas son las diferencias:

  • Vanillajs, sin dependencias
  • No espere a setTimeoutque maneje el controlador de clic o doble clic
  • Al hacer doble clic en él, primero se activa el controlador de clic, luego el controlador de doble 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));

A continuación se muestra el uso en un jsfiddle, el botón jQuery es el comportamiento de la respuesta aceptada.

jsfiddle

A1rPun
fuente
2
El código anterior y la versión 'Vanilla' de su violín no funcionan ... aquí hay una versión Vanilla fija: jsfiddle.net/jeum/cpbwx5vr/19
jeum
@jeum Todavía me funciona en todos los navegadores. ¿Qué "no funciona" y qué esperas? Parece que su versión no está haciendo lo que pretendía.
A1rPun
En primer lugar, modifiqué mi versión (se eliminó el doble cierre), pruebe la nueva: jsfiddle.net/jeum/cpbwx5vr/20 El problema con su violín (versión Vanilla) es que el doble clic activa el controlador único: recupera un solo + doble para mí.
jeum
@jeum Ese da un error. Sí, mi respuesta difiere de las respuestas aceptadas y otras aquí y también especifico esta diferencia en esta línea: Dispare un clic, luego un doble clic (no vaya directamente a hacer doble clic)
A1rPun
1
Sí, error nuevamente, por lo que esta versión responde a la pregunta principal: jsfiddle.net/jeum/cpbwx5vr/21 . Ahora con respecto a tu versión (es cierto que no la había entendido), ¿has notado que 'jQuery' no logra lo que quieres en tu violín?
jeum
5

Otra solución simple de Vanilla basada en la respuesta de A1rPun (vea su violín para la solución jQuery, y ambas están en esta ).

Parece que para NO activar un controlador de un solo clic cuando el usuario hace doble clic, el controlador de un solo clic se activa necesariamente después de un retraso ...

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
fuente
3
De hecho, esta es la mejor alternativa si no desea que se dispare el clic único :)
A1rPun
Cuando event.detailestá disponible, es la mejor manera de detectar un doble clic desde el controlador de clics. Vea esta respuesta .
Carl G
5

Aquí hay una alternativa del código de jeum para un número arbitrario de eventos:

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

Necesitaba esto para una aplicación cytoscape.js .

nex
fuente
¡Agradable! también podemos declarar una nueva variable dentro de la función devuelta y asignarla con this, que es el elemento en el que se hace clic, y pasarlo al controlador (al lado eo en lugar de él).
HeyJude
5

¿Cómo diferenciar entre clics simples y clics dobles en un mismo elemento?

Si no es necesario mezclarlos, se puede confiar en clicky dblclicky cada uno va a hacer el trabajo muy bien.

Surge un problema al intentar mezclarlos: un dblclickevento también activará un clickevento , por lo que debe determinar si un solo clic es un solo clic "independiente" o parte de un doble clic.

Además: no debe usar ambos clicky dblclicken el mismo elemento :

No es aconsejable vincular controladores a los eventos click y dblclick para el mismo elemento. La secuencia de eventos desencadenados varía de un navegador a otro, algunos reciben dos eventos de clic antes del dblclick y otros solo uno. La sensibilidad del doble clic (tiempo máximo entre los clics que se detecta como un doble clic) puede variar según el sistema operativo y el navegador, y a menudo es configurable por el usuario.
Fuente: https://api.jquery.com/dblclick/

Ahora pasemos a las buenas noticias:

Puede utilizar la detailpropiedad del evento para detectar la cantidad de clics relacionados con el evento. Esto hace que los clics dobles en el interior sean clickbastante fáciles de detectar.

El problema sigue siendo la detección de clics individuales y si forman parte de un doble clic o no. Para eso, volvemos a usar un temporizador y setTimeout.

Envolviendo todo junto, con el uso de un atributo de datos (para evitar una variable global) y sin la necesidad de contar los clics nosotros mismos, obtenemos:

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>

Manifestación:

JSfiddle


Notas sobre accesibilidad y velocidades de doble clic:

  • Como dice Wikipedia, "el retraso máximo requerido para que dos clics consecutivos se interpreten como un doble clic no está estandarizado".
  • No hay forma de detectar la velocidad de doble clic del sistema en el navegador.
  • Parece que el valor predeterminado es 500 ms y el rango 100-900 mms en Windows ( fuente )
  • Piense en las personas con discapacidades que establecen, en la configuración de su sistema operativo, la velocidad de doble clic a su nivel más lento.
    • Si la velocidad de doble clic del sistema es más lenta que los 500 ms anteriores predeterminados, se activarán los comportamientos de clic único y doble.
    • O no utilice la función de hacer clic combinado simple y doble en un mismo elemento.
    • O: agregue una configuración en las opciones para tener la capacidad de aumentar el valor.

Me tomó un tiempo encontrar una solución satisfactoria, ¡espero que esto ayude!

Fabien Snauwaert
fuente
4

Utilice el excelente complemento jQuery Sparkle. El complemento le da la opción de detectar el primer y el último clic. Puede usarlo para diferenciar entre clic y doble clic detectando si otro clic fue seguido por el primer clic.

Compruébalo en http://balupton.com/sandbox/jquery-sparkle/demo/

Hussein
fuente
3

Escribí un complemento de jQuery simple que te permite usar un evento personalizado de 'singleclick' para diferenciar un solo clic de un doble 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
fuente
3

La respuesta correcta moderna es una mezcla entre la respuesta aceptada y la solución de @kyw. Necesita un tiempo de espera para evitar ese primer clic y la event.detailmarca para evitar el segundo 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>


fuente
1

Me gusta evitar jquery (y otras bibliotecas de 90-140k), y como los navegadores señalados manejan onclick primero, esto es lo que hice en un sitio web que creé (este ejemplo también cubre cómo obtener una ubicación local xy en la que se hizo clic)

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

Espero que ayude

dako
fuente
2
No se requiere la URL de su juego para comprender su respuesta en absoluto. Lo eliminaré para que esta publicación no se considere un intento de spam.
Andrew Barber
1
el único inconveniente, 200 es una constante mágica y puede variar drásticamente de la configuración del mouse del usuario en el sistema operativo
Danubian Sailor
1

Basado en la respuesta de Adrien Schuler (¡muchas gracias!), Para Datatables.net y para muchos usos, aquí hay una modificación:

Función

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

Utilizar

$("#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
fuente
0

esto funcionó para mí

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

uso-

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

Simplemente publique la respuesta HTML nativa en caso de que la necesidad sea fácil y HTML.

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

Esto, por supuesto, tiene opciones nativas de Jquery. es decir ... $('#id').attr('ondblclick',function(){...})o, como se dijo anteriormente,$('#id').dblclick(function(){...});

JSG
fuente
0

Sé que esto es antiguo, pero a continuación se muestra un único ejemplo de JS de un contador de bucle básico con un solo temporizador para determinar un clic simple o doble. Ojalá esto ayude a alguien.

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 Moisés
fuente