2012-05-29 10 views
11

Probé con el evento 'tap' móvil de jquery y encontré que disparó dos veces, cada vez que se activa. Código de la siguiente manera para una página HTML:evento de jQuery móvil tap activado por dos veces

<!DOCTYPE html> 
<html> 
<head> 
    <title>Demo</title> 
    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">  
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>  
    <script src="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.js"></script>  
    <style> 
     #box{ 
      background-color:red; 
      width:200px; 
      height:200px; 
     } 
    </style> 
</head> 
<body> 
    <div id="box"> 
     tapped me 
    </div> 
    <script type="text/javascript"> 
     $(document).ready(function() { 
      $('#box').bind('tap',function(event) { 
       alert('why'); 
      }); 
     }); 
    </script> 
</body> 
</html> 

Más irónico es cuando pruebo esto una jsFiddle, sólo se activa el evento de una sola vez .

Aquí está el enlace. http://jsfiddle.net/mochatony/tzQ6D/6/

Después de más pruebas descubrí que el error se ha ido con la colocación de la sección javascript en el encabezado.

<!DOCTYPE html> 
<html> 
<head> 
    <title>Demo</title> 
    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">  
    <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"> 
    </script> 
    <script type="text/javascript" src="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.js"> 
    </script> 
    <style type="text/css"> 
     #box{ background-color:red; width:200px; height:200px; } 
    </style> 
    <script type="text/javascript"> 
     $(document).ready(function() { 
      $('#box').bind('tap', function(event) { 
       alert('halo'); 
      }); 
     }); 
    </script>   
</head> 
<body> 
    <div id="box"> 
     tapped me 
    </div> 
</body> 
</html> 

No pude explicar por qué la ubicación en el cuerpo y la sección del encabezado hacen que esto sea diferente.

Respuesta

5

del jQuery Mobile page:

Importante: Utilice $ (document) .bind ('pageinit'), no $ (document) ready()
El primero que se aprende en jQuery es para llamar al código dentro de la función $ (document) .ready() para que todo se ejecute tan pronto como se cargue DOM. Sin embargo, en jQuery Mobile, Ajax se usa para cargar el contenido de cada página en el DOM mientras navega, y el controlador DOM listo solo se ejecuta para la primera página. Para ejecutar código cada vez que se carga y se crea una nueva página , puede vincularse al evento pageinit. Este evento se explica en detalle en la parte inferior de esta página.

omita el $(document).ready(). más información here.

+2

Gracias por la respuesta. Hizo una prueba con pageinit, el evento pageinit también se disparó dos veces. Pruebo tanto en Firefox como en Chrome. Me parece extraño. – TonyTakeshi

9

Estás experimentando el problema del clic fantasma ... Es un conocido "error" y difícil de resolver.

Mas informaciones allí:

http://forum.jquery.com/topic/tap-fires-twice-with-live-tap https://developers.google.com/mobile/articles/fast_buttons http://philosopherdeveloper.wordpress.com/2011/11/01/ghost-clicks-in-jquery-mobile/

En el primer enlace que encontrará un truco que hace el truco. Por lo que sé, no hay una solución fácil :(

BTW: Aunque no resuelva su problema, @Sagiv es correcto. JQuery mobile a menudo usa ajax para cambiar de página y no desencadena un documento. evento ready.

+1

Gracias por la respuesta. Descubrí que el problema desapareció si coloco el código en la sección del encabezado. No tengo idea por qué. – TonyTakeshi

15

me olvido donde vi esto, pero el problema es que jQuery Mobile es vinculante para ambos eventos de toque y el ratón con el fin de simular el "toque", y en algunas circunstancias Android disparará ambos.

El truco que me ha funcionado es llamar al preventDefault en el evento en su controlador de eventos. Esto evitará que el evento duplicado se active.

En cuanto a por qué este es el caso solo algunas veces, sé que los navegadores móviles intentarán disparar la versión del mouse del evento si alguien no está escuchando la versión táctil. Puede haber un problema con la detección o la delegación de jQuery que confunde esa heurística.

+0

En el caso en que los eventos del mouse y los eventos táctiles se activan, al devolver false en combinación con preventDefault debería arreglarlo en la mayoría de los navegadores (quizás todos). – logic8

+0

Sí, esto parece funcionar para nosotros también. Puedo confirmar que, al usar jquery mobile 1.4.2, experimentamos este comportamiento y al poner e.preventDefault() resolvió el problema para nosotros. –

+2

¡Es increíble! En mi caso puse ** e.preventDefault(); ** después de todas las acciones en '$ ('. Selector'). On ('click touchrt', función (e) {})' función y magia happend. W/o ** e.preventDefault(); ** el evento touchstart provocó un doble clic/toque. Muchas gracias, hombre! –

0

Descubrí que en mi caso la adición de data-role="page" al contenedor de mi página evitaba que los eventos de toque se dispararan dos veces.

1
$("#buttonID").tap(function(event){ 
     if(localStorage.JQMGostClick == 0 || localStorage.JQMGostClick == "" || typeof(localStorage.JQMGostClick) === "undefined") 
      localStorage.JQMGostClick = 1; 
     else if(localStorage.JQMGostClick == 1){ 
      localStorage.JQMGostClick = 0; 
      return false; 
     } 
..... 
}); 

Funciona para mí, ya que si se está utilizando un entorno móvil, entonces probablemente está utilizando un tipo de almacenamiento

0

he experimentado algo como esto antes y fue debido al hecho de que mi forma era no dentro de una data-role="page"

Lo que sugeriría es para envolver su código con la estructura html jQuery Mobile para que su podría debería tener este lugar

<div data-role="page" class="ui-page ui-page-theme-a ui-page-active"> 
    <div class="ui-content"> 
    <div id="box"> 
     tapped me 
    </div> 
    <script type="text/javascript"> 
     $(document).ready(function() { 
      $('#box').bind('tap',function(event) { 
       alert('why'); 
      }); 
     }); 
    </script> 
    </div> 
</div> 
0

Puede que esta no sea la mejor solución y solo funcionará en algunos casos, pero lo que funcionó para mí fue inmediatamente después de que el evento de clic comenzara a establecer los 'eventos de puntero' de CSS para ese elemento en 'ninguno'. Luego, utilizando setTimeout de JS, restablece los 'eventos de puntero' a automático después de 500 ms.

Para mí, 300ms era suficiente para dispositivos Android, pero el iPhone necesitaba 500ms para evitar el doble clic.

function yourEvent(evt){ 
 

 
    $(el).css('pointer-events', 'none'); 
 
    
 
    setTimeout(function(){ 
 
     $(el).css('pointer-events', 'auto'); 
 
    }, 500); 
 
    
 
    //do you stuff 
 

 
}

2

relacionados con esta cuestión, que estaba recibiendo dos eventos 'grifo' y 'clic' uno justo después del otro. Todas las ideas aquí fueron inspiradoras, pero terminé encontrando otra solución. Agregué el siguiente código a mi controlador JavaScript para discriminar sucesos duplicados consecutivos basados ​​en la marca de tiempo que, afortunadamente, es exactamente el mismo para los dos eventos duplicados. Básicamente, lo que hago es almacenar la última marca de tiempo utilizada si decido consumir el evento. La segunda vez que un evento con la misma marca de tiempo lo descarté.

var _lastEventTimestamp; 
 
var checkAndPreventDuplicatedEvent = function (e) { 
 
    if (e.timeStamp === _lastEventTimestamp) return true; 
 
    else _lastEventTimestamp = e.timeStamp; 
 
    return false; 
 
}

entonces, en cada una de mis manejadores he añadido el código de filtrado en el principio:

var onTapSomething = function (e) { 
 
    if (checkAndPreventDuplicatedEvent(e)) return;   
 
    //do here whatever you would do in the case of legitimate event... 
 
}

+0

uno más, puede usar la misma estrategia para deshacerse también de algunos eventos de "ruido" por si acaso. Estaba teniendo algunos problemas en Android ... que elimino usando esta versión modificada del filtro anterior: var checkAndPreventDuplicatedEvent = function (e) { if ((e.timeStamp - _lastEventTimestamp) <1000) return true; else _lastEventTimesTime = e.timeStamp; devuelve falso; } – pabloelustondo

Cuestiones relacionadas