Estoy trabajando en un sitio web móvil que tiene que funcionar en una variedad de dispositivos. El que me está dando dolor de cabeza en este momento es BlackBerry.
Necesitamos admitir tanto los clics del teclado como los eventos táctiles.
Idealmente, solo usaría:
$thing.click(function(){...})
pero el problema con el que nos encontramos es que algunos de estos dispositivos blackberry tienen un retraso muy molesto desde el momento en que se toca hasta que se activa un clic.
El remedio es usar touchstart en su lugar:
$thing.bind('touchstart', function(event){...})
Pero, ¿cómo hago para vincular ambos eventos, pero solo para disparar uno? Todavía necesito el evento de clic para dispositivos de teclado, pero, por supuesto, no quiero que se active el evento de clic si estoy usando un dispositivo táctil.
Una pregunta adicional: ¿hay alguna forma de hacer esto y, además, acomodar navegadores que ni siquiera tienen un evento de inicio táctil? Al investigar esto, parece que BlackBerry OS5 no es compatible con el inicio táctil, por lo que también tendrá que depender de los eventos de clic para ese navegador.
APÉNDICE:
Quizás una pregunta más completa es:
Con jQuery, ¿es posible / recomendado manejar las interacciones táctiles y las interacciones del mouse con los mismos enlaces?
Idealmente, la respuesta es sí. Si no, tengo algunas opciones:
1) Usamos WURFL para obtener información del dispositivo para poder crear nuestra propia matriz de dispositivos. Dependiendo del dispositivo, usaremos touchstart O haremos clic.
2) Detectar soporte táctil en el navegador a través de JS (necesito investigar un poco más sobre eso, pero parece que es factible).
Sin embargo, eso todavía deja un problema: ¿qué pasa con los dispositivos que admiten AMBOS? Algunos de los teléfonos que admitimos (a saber, Nokias y BlackBerries) tienen pantallas táctiles y teclados. Entonces, eso me lleva de vuelta a la pregunta original ... ¿hay alguna manera de permitir ambas cosas a la vez de alguna manera?
fuente
.bind('touchstart mouseup')
lo resolverá (según uno de los comentarios a continuación)Respuestas:
Actualización : Echa un vistazo al proyecto PolyQill de jQuery Pointer Events que te permite enlazar eventos de "puntero" en lugar de elegir entre el mouse y el toque.
Enlace a ambos, pero haga una bandera para que la función solo se active una vez cada 100 ms o menos.
fuente
click
cambiarlo amousedown
... tal vez el gran retraso sea la diferencia entremousedown
ymouseup
cuál es la forma en queclick
se determina.touchend
aplicando una clase detouched
. Esto se dispara antes de que se llame al evento click. Luego agrego un evento de clic que primero verifica la existencia de esa clase. Si está allí, asumimos que se activaron los eventos táctiles y no hacemos nada con un clic que no sea eliminar el nombre de la clase para 'restablecerlo' para la próxima interacción. Si la clase no está allí, entonces asumimos que habían usado un teclado para hacer clic en el elemento y activar la función desde allí.Esta es la solución que "creo" y saca GhostClick e implementa FastClick. Pruebe por su cuenta y háganos saber si funcionó para usted.
fuente
event.handled
será igualundefined
cada vez que se active el evento. Aquí hay una solución: establezca el indicador 'manejado' en el elemento de destino mediantejQuery.data()
.event.stopPropagation();
yevent.preventDefault();
desde mi entendimiento (y prueba), el evento solo se puede disparar una vez con esto. Entonces, ¿por qué incluso verificarif(event.handled !== true)
? Para mí no es necesario o me pierdo algo?event.handled
debe verificar el valortrue
? Por lo que puedo decir, nunca esfalse
. Comienza comoundefined
, y luego desea saber si se ha configurado comotrue
.Podrías probar algo como esto:
fuente
Por lo general, esto también funciona:
fuente
Solo agregar
return false;
al final de laon("click touchstart")
función de evento puede resolver este problema.De la documentación de jQuery en .on ()
fuente
Tenía que hacer algo similar. Aquí hay una versión simplificada de lo que funcionó para mí. Si se detecta un evento táctil, elimine el enlace de clic.
En mi caso, el evento de clic estaba vinculado a un
<a>
elemento, así que tuve que eliminar el enlace de clic y volver a vincular un evento de clic que impedía la acción predeterminada para el<a>
elemento.fuente
Tuve éxito de la siguiente manera.
Pan comido...
fuente
e
parámetro enfunction()
Creo que la mejor práctica es usar ahora:
EJEMPLO
EDITAR (2017)
A partir de 2017, los navegadores que comienzan con Chrome y dan pasos para hacer que el evento de clic sea
.on("click")
más compatible tanto para el mouse como para el tacto, eliminando el retraso generado por los eventos de toque en las solicitudes de clic.Esto lleva a la conclusión de que volver a usar solo el evento de clic sería la solución más simple para avanzar.
Todavía no he hecho ninguna prueba de navegador cruzado para ver si esto es práctico.
fuente
mouseup
resultados impredecibles, especialmente cuando uso un trackpad en lugar de un mouse tradicional.Por lo general, no desea mezclar la API predeterminada táctil y no táctil (clic). Una vez que ingresa al mundo táctil, es más fácil tratar solo con las funciones táctiles. A continuación hay un pseudocódigo que haría lo que usted quisiera.
Si se conecta en el evento touchmove y rastrea las ubicaciones, puede agregar más elementos en la función doTouchLogic para detectar gestos y otras cosas.
fuente
verifique los botones rápidos y los clics de chost desde google https://developers.google.com/mobile/articles/fast_buttons
fuente
Bueno ... Todos estos son súper complicados.
Si tienes modernizador, es obvio.
fuente
Otra implementación para un mejor mantenimiento. Sin embargo, esta técnica también hará event.stopPropagation (). El clic no se detecta en ningún otro elemento que hizo clic durante 100 ms.
fuente
Solo para fines de documentación, esto es lo que he hecho para el clic más rápido / más rápido en el escritorio / toque en la solución móvil que se me ocurre:
Reemplacé la
on
función de jQuery por una modificada que, cada vez que el navegador admite eventos táctiles, reemplaza todos mis eventos de clic con inicio táctil.Uso que sería exactamente el mismo que antes, como:
Pero usaría touchstart cuando esté disponible, haga clic cuando no lo esté. No se necesitan retrasos de ningún tipo: D
fuente
Se me ocurrió la idea de memorizar si
ontouchstart
alguna vez se activó. En este caso, estamos en un dispositivo que lo admite y queremos ignorar elonclick
evento. Comoontouchstart
siempre debe activarse antesonclick
, estoy usando esto:fuente
Podrías intentarlo así:
fuente
En mi caso esto funcionó perfectamente:
El principal problema fue cuando en lugar de mouseup probé con clic, en dispositivos táctiles activé clic y toque al mismo tiempo, si uso el clic apagado, alguna funcionalidad no funcionó en absoluto en dispositivos móviles. El problema con el clic es que es un evento global que dispara el resto del evento, incluido el touchend.
fuente
Esto funcionó para mí, el móvil escucha a ambos, así que evita el uno, que es el evento táctil. El escritorio solo escucha el mouse.
fuente
Siendo para mí la mejor respuesta de Mottie, solo estoy tratando de hacer su código más reutilizable, así que esta es mi contribución:
fuente
También estoy trabajando en una aplicación web para Android / iPad, y parece que si solo usa "touchmove" es suficiente para "mover componentes" (no es necesario el inicio táctil). Al deshabilitar el inicio táctil, puede usar .click (); de jQuery. En realidad está funcionando porque no ha sido sobrecargado por touchstart
Finalmente, puede binb .live ("touchstart", función (e) {e.stopPropagation ();}); para pedirle al evento de inicio táctil que deje de propagarse, haga clic en la sala de estar () para activarse.
Funcionó para mi.
fuente
touchstart
?Hay muchas cosas a tener en cuenta al intentar resolver este problema. La mayoría de las soluciones rompen el desplazamiento o no manejan correctamente los eventos de clic fantasma.
Para obtener una solución completa, consulte https://developers.google.com/mobile/articles/fast_buttons
NB: No puede manejar eventos de clic fantasma por elemento. La ubicación de la pantalla activa un clic retrasado, por lo que si sus eventos táctiles modifican la página de alguna manera, el evento de clic se enviará a la nueva versión de la página.
fuente
Puede ser efectivo asignar a los eventos
'touchstart mousedown'
o'touchend mouseup'
evitar efectos secundarios no deseados del usoclick
.fuente
Aprovechando el hecho de que un clic siempre seguirá a un evento táctil, esto es lo que hice para deshacerme del "clic fantasma" sin tener que usar tiempos de espera o banderas globales.
Básicamente, cada vez
ontouchstart
que se dispara un evento en el elemento, se marca un conjunto y luego se elimina (e ignora), cuando llega el clic.fuente
¿Por qué no usar la API de eventos jQuery?
http://learn.jquery.com/events/event-extensions/
He usado este simple evento con éxito. Es limpio, espacio de nombres y lo suficientemente flexible como para mejorar.
fuente
Si está utilizando jQuery, lo siguiente funcionó bastante bien para mí:
Otras soluciones también son buenas, pero estaba vinculando múltiples eventos en un bucle y necesitaba la función de auto llamada para crear un cierre apropiado. Además, no quería deshabilitar el enlace ya que quería que se pueda invocar en el siguiente clic / inicio táctil.
¡Podría ayudar a alguien en una situación similar!
fuente
Para funciones simples, simplemente reconozca tocar o hacer clic. Uso el siguiente código:
Esto devolverá "touch" si el evento touchstart está definido y "no touch" si no. Como dije, este es un enfoque simple para eventos de clic / toque.
fuente
Estoy intentando esto y hasta ahora funciona (pero solo estoy en Android / Phonegap, por lo tanto, advertencia)
No me gusta el hecho de que estoy volviendo a vincular los controladores en cada toque, pero todas las cosas consideradas toques no ocurren muy a menudo (¡en tiempo de computadora!)
Tengo una TONELADA de controladores como el del '# teclado', por lo que tener una función simple que me permite lidiar con el problema sin demasiado código es la razón por la que elegí este camino.
fuente
Intenta usar
Virtual Mouse (vmouse) Bindings
desdejQuery Mobile
. Es un evento virtual especialmente para su caso:http://api.jquerymobile.com/vclick/
Lista de soporte del navegador: http://jquerymobile.com/browser-support/1.4/
fuente
EDITAR: Mi respuesta anterior (basada en las respuestas en este hilo) no era el camino a seguir para mí. Quería que un submenú se expandiera al entrar con el mouse o al hacer clic con el botón táctil y al contraerse con el botón izquierdo del mouse u otro clic táctil. Dado que los eventos del mouse normalmente se activan después de los eventos táctiles, fue un poco complicado escribir oyentes de eventos que admitan la entrada de la pantalla táctil y del mouse al mismo tiempo.
Complemento jQuery: toque o mouse
Terminé escribiendo un complemento jQuery llamado " Touch or Mouse " (897 bytes minified) que puede detectar si un evento fue invocado por una pantalla táctil o un mouse (¡sin probar el soporte táctil!). Esto permite la compatibilidad con la pantalla táctil y el mouse al mismo tiempo. y separa completamente sus eventos.
De esta forma, el OP puede usar
touchstart
otouchend
para responder rápidamente a los clics táctiles yclick
para los clics invocados solo con un mouse.Demostración
Primero hay que hacer ie. el elemento del cuerpo sigue los eventos táctiles:
Los eventos del mouse están vinculados a los elementos de la forma predeterminada y al llamar
$body.touchOrMouse('get', e)
podemos averiguar si el evento fue invocado por una pantalla táctil o un mouse.Vea el complemento en funcionamiento en http://jsfiddle.net/lmeurs/uo4069nh .
Explicación
touchstart
ytouchend
eventos, de esta manera eltouchend
evento no tiene que ser disparado en el elemento desencadenante (es decir, un enlace o botón). Entre estos dos eventos táctiles, este complemento considera que cualquier evento del mouse se invoca mediante el tacto.touchend
, cuando se dispara un evento del mouse dentro deghostEventDelay
(opción, 1000ms por defecto) despuéstouchend
, este complemento considera que el evento del mouse se invoca mediante el tacto.:active
estado. Elmouseleave
evento solo se dispara después de que el elemento pierde este estado por ej. haciendo clic en otro elemento. Como esto podría ser segundos (¡o minutos!) Después demouseenter
que se haya disparado el evento, este complemento realiza un seguimiento del últimomouseenter
evento de un elemento : si el últimomouseenter
evento fue invocado por contacto, el siguientemouseleave
evento también se considera invocado por contacto.fuente
Aquí hay una manera simple de hacerlo:
Básicamente, guarda el primer tipo de evento que se activa en la propiedad 'trigger' en el objeto de datos de jQuery que está adjunto al documento raíz, y solo se ejecuta cuando el tipo de evento es igual al valor en 'trigger'. En dispositivos táctiles, la cadena de eventos probablemente sería 'touchstart' seguido de 'click'; sin embargo, el controlador 'clic' no se ejecutará porque "clic" no coincide con el tipo de evento inicial guardado en "disparador" ("inicio táctil").
La suposición, y creo que es segura, es que su teléfono inteligente no cambiará espontáneamente de un dispositivo táctil a un dispositivo de mouse o de lo contrario el toque nunca se registrará porque el tipo de evento 'disparador' solo se guarda una vez por la carga de la página y el "clic" nunca coincidirían con el "inicio táctil".
Aquí hay un codepen con el que puede jugar (intente tocar el botón en un dispositivo táctil; no debería haber retraso de clic): http://codepen.io/thdoan/pen/xVVrOZ
También implementé esto como un simple complemento jQuery que también admite el filtrado de descendientes de jQuery al pasar una cadena de selección:
Codepen: http://codepen.io/thdoan/pen/GZrBdo/
fuente
$.data()
para almacenar datos a los que pueden acceder múltiples funciones pero que no pertenecen al ámbito global. Una ventaja es que, dado que lo estoy almacenando en un elemento, naturalmente me proporciona más contexto.El mejor método que he encontrado es escribir el evento táctil y hacer que ese evento llame al evento de clic normal mediante programación. De esta manera, tiene todos sus eventos de clic normales y luego necesita agregar un solo controlador de eventos para todos los eventos táctiles. Para cada nodo que desee que sea táctil, simplemente agregue la clase "táctil" para invocar el controlador táctil. Con Jquery funciona así con cierta lógica para asegurarse de que sea un evento táctil real y no un falso positivo.
fuente