2010-06-23 22 views
11

Estoy creando un sitio en Safari para iPad. Me necesidad de prevenir el zoom en el evento tocando dos veces, pero tengo dos problemas:Safari iPad: evitar el zoom al tocar dos veces

  • un doble toque no genera ningún evento, por lo que no puede utilizar "event.preventDefault();"
  • Necesito hacer esto solo cuando se cumplen algunas condiciones, así que no puedo usar la etiqueta "<meta name = "viewport" content = "user-scalable = no">" ... Si lo hiciera, los usuarios nunca podrían hacer zoom en mi página.

¿Cómo puedo solucionar estos problemas?

Respuesta

7

Mobile Safari no es compatible con el evento javascript ondblclick. Safari lo interpreta como un "zoom".

Raúl Sánchez ha publicado una posible solución: http://appcropolis.com/implementing-doubletap-on-iphones-and-ipads/

+2

He usado esta solución de hecho ... ¡Este tema está realmente detallado, gracias! Para los visitantes, la idea principal es la siguiente: Primero, atrapa un evento de "toque". Luego, si se lanza otro evento "toque" antes de 500ms: es un "toque doble", por lo que si puede detener el evento aquí -> sin "doble toque" :) Consulte el enlace para obtener más explicaciones. – Nicolas

7

aquí hay un plugin de jQuery que escribí para el mismo propósito - deshabilitar selectivamente zoom pulse dos veces en los elementos de página dados (en mi caso, botones de navegación para voltear páginas) Quiero responder a cada toque (incluido el doble toque) como un evento de clic normal, sin iOS "toque mágico".

Para usarlo, simplemente ejecute algo como $('.prev,.next').nodoubletapzoom(); en los elementos que le interesan. (Editar: ahora también ignora pellizcos)

// jQuery no-double-tap-zoom plugin 

// Triple-licensed: Public Domain, MIT and WTFPL license - share and enjoy! 

(function($) { 
    var IS_IOS = /iphone|ipad/i.test(navigator.userAgent); 
    $.fn.nodoubletapzoom = function() { 
    if (IS_IOS) 
     $(this).bind('touchstart', function preventZoom(e) { 
     var t2 = e.timeStamp 
      , t1 = $(this).data('lastTouch') || t2 
      , dt = t2 - t1 
      , fingers = e.originalEvent.touches.length; 
     $(this).data('lastTouch', t2); 
     if (!dt || dt > 500 || fingers > 1) return; // not double-tap 

     e.preventDefault(); // double tap - prevent the zoom 
     // also synthesize click events we just swallowed up 
     $(this).trigger('click').trigger('click'); 
     }); 
    }; 
})(jQuery); 
+0

Esto funciona, pero tiene un error: más que dos toque. Añada esto después de activar los clics eliminados: '$ (this) .data ('lastTouch', 0);'. Sin ella, obtienes cuatro clics cuando tocas tres veces (es posible más con el cuádruple toque). Con él obtienes tres clics en triple toque, cuatro clic en cuádruple toque. La idea es que es posible que tengas un elemento que debería responder a muchos toques consecutivos (en lugar de ser retenido, por las razones que sean). –

+0

Esta solución parece evitar todos los clics repetidos, si la demora entre ellos es inferior a 500 ms. ¿De alguna manera sería posible permitir cliquear, por ejemplo? 5 veces en un marco de tiempo de 500ms Y ¿aún así previene el acercamiento? Necesitaría una forma en la que los clics repetidos funcionen en los dispositivos de mouse. –

+0

Encontré una solución simple a mi problema con el tirador: http://stackoverflow.com/a/30744654/1691517. No "espera" 500 ms hasta que permite un nuevo clic, pero lo hace de inmediato, pero aún impide el acercamiento indeseado. –

1

simplemente doten de visualización puede no ser siempre suficiente - en algunos casos puede que tenga que llamar también event.preventDefault(); en el controlador Touchstart.

5

Modifiqué la solución javascript de @ ecmanaut para hacer dos cosas.

  1. Uso modernizr, por lo que pondrá una clase .touch css en el nodo html, por lo que puedo detectar pantallas táctiles en lugar de utilizar la detección de agente de usuario. Tal vez haya un enfoque de "modernizr-less", pero no lo sé.
  2. Separa cada "clic" para que ocurran por separado, si hace clic una vez, hará clic una vez, si hace clic rápidamente en el botón/disparador, contará varias veces.
  3. cambios menores en el formato del código, prefiero que cada var se defina por separado, etc., esto es más un "yo" que otra cosa, supongo que podría revertir eso, no pasará nada malo.

Creo que estas modificaciones hacen que sea mejor, porque puedes incrementar un contador 1,2,3,4 lugar de 2,4,6,8

aquí es el código modificado:

// jQuery no-double-tap-zoom plugin 
// Triple-licensed: Public Domain, MIT and WTFPL license - share and enjoy! 
// 
// [email protected]: I modified this to 
// use modernizr and the html.touch detection and also to stop counting two 
// clicks at once, but count each click separately. 

(function($) { 
    $.fn.nodoubletapzoom = function() { 
     if($("html.touch").length == 0) return; 

     $(this).bind('touchstart', function preventZoom(e){ 
      var t2 = e.timeStamp; 
      var t1 = $(this).data('lastTouch') || t2; 
      var dt = t2 - t1; 
      var fingers = e.originalEvent.touches.length; 
      $(this).data('lastTouch', t2); 
      if (!dt || dt > 500 || fingers > 1){ 
       return; // not double-tap 
      } 
      e.preventDefault(); // double tap - prevent the zoom 
      // also synthesize click events we just swallowed up 
      $(this).trigger('click'); 
     }); 
    }; 
})(jQuery); 

la aplicar el nodoubletapzoom() a la etiqueta del cuerpo, como este

$("body").nodoubletapzoom(); 

su construcción html, debe ser algo como esto

<body> 
    <div class="content">...your content and everything in your page</div> 
</body> 

Luego, en su Javascript, vincular a su clic manipuladores como esto

$(".content") 
    .on(".mydomelement","click",function(){...}) 
    .on("button","click",function(){...}) 
    .on("input","keyup blur",function(){...}); 
    // etc etc etc, add ALL your handlers in this way 

puedes usar cualquier controlador de eventos de jQuery y cualquier nodo dom. ahora no tienes que hacer nada más que eso, tienes que conectar todos los manejadores de eventos de esta manera, no lo he intentado de otra manera, pero de esta manera funciona absolutamente sólido, puedes literalmente golpear la pantalla 10 veces por segundo y duerma zoom y registra los clics (obviamente no 10 por segundo, el iPad no es tan rápido, lo que quiero decir es, no se puede disparar el zoom)

Creo que esto funciona porque está adjuntando el nozoom manipular al cuerpo y luego asociar todos los manejadores de eventos al nodo ".content", pero delegando al nodo específico en cuestión, por lo tanto, jquery captura a todos los manejadores en la última etapa antes de que el evento suba a la etiqueta corporal.

El principal beneficio de esta solución es que solo tiene que asignar el manejador nodoubletapzoom() al cuerpo, solo lo hace una vez, no una vez para cada elemento, por lo que requiere menos trabajo, esfuerzo y pensamiento para poder terminar las cosas.

esto tiene la ventaja adicional de que si agrega contenido usando AJAX, automáticamente tienen los controladores listos y en espera, supongo que si usted NO QUISIERA eso, entonces este método no funcionará para usted y tendrá que ajústalo más

He verificado que este código funciona en ipad, es realmente hermoso, ¡bien hecho a @ecmanaut por la solución principal!

** Modificado el sábado 26 de mayo debido a que encontré lo que parece ser una solución perfecta con un esfuerzo absolutamente mínimo

0

La respuesta aceptada 'doble click' es para mí un poco de 'hinchado' y el uso de una marca de tiempo .. ... ¿por qué? Mire esta simple implementación sin excesiva "hinchazón".

function simulateDblClickTouchEvent(oo) 
{ 
var $oo = !oo?{}:$(oo); 
if(!$oo[0]) 
    { return false; } 

$oo.bind('touchend', function(e) 
{ 
    var ot = this, 
    ev = e.originalEvent; 

    if(ev && typeof ev.touches == 'object' && ev.touches.length > 1) 
    { return; } 

    ot.__taps = (!ot.__taps)?1:++ot.__taps; 

    if(!ot.__tabstm) // don't start it twice 
    { 
    ot.__tabstm = setTimeout(function() 
    { 
     if(ot.__taps >= 2) 
     { ot.__taps = 0; 
      $(ot).trigger('dblclick'); 
     } 
     ot.__tabstm = 0; 
     ot.__taps = 0; 
    },800); 
    } 
}); 
return true; 
}; 

Uso:

simulateDblClickTouchEvent($('#example')); 

or 

simulateDblClickTouchEvent($('.example')); 

función devuelve verdadero o falso cuando el evento se enganchan o no.

Para evitar que las cosas zoom y desplazarse hacer esto:

function disableTouchScroll() 
{ 

try { 
    document.addEventListener('touchmove', function(e) { e.preventDefault(); }, true); 
    $j('body')[0].addEventListener('touchmove', function(e) { e.preventDefault(); }, true); 
    } 
    catch(ee) { return false; } 
    return true; 
} 

también con CSS es fácil de evitar el zoom:

body * { -webkit-user-select:none; } 
  • = no es eficiente, pero probarlo, funciona muy bien.

¡Salud!

6

prueba este código modificado. Se debe trabajar para ambos dispositivos Android y iOS

(function($) { 
$.fn.nodoubletapzoom = function() { 
    $(this).bind('touchstart', function preventZoom(e){ 
     var t2 = e.timeStamp; 
     var t1 = $(this).data('lastTouch') || t2; 
     var dt = t2 - t1; 
     var fingers = e.originalEvent.touches.length; 
     $(this).data('lastTouch', t2); 
     if (!dt || dt > 500 || fingers > 1){ 
      return; // not double-tap 
     } 
     e.preventDefault(); // double tap - prevent the zoom 
     // also synthesize click events we just swallowed up 
     $(e.target).trigger('click'); 
    }); 
}; 
})(jQuery); 

luego aplicar el nodoubletapzoom() para el cuerpo de la etiqueta

$("body").nodoubletapzoom(); 
+0

¡Gracias por esto! Hice un ejemplo: http://jsbin.com/dihoxedika/1/. El problema en el código de ecmanauts era '$ (this) .trigger ('click'). Trigger ('click')'. Cuando reemplacé 'this' con' e.target' y eliminé el segundo activador, comenzó a funcionar en Android Chrome. El problema era que los clics repetidos rápidos no eran posibles. –

+0

por favor acepte la respuesta si es relevante – Inventillect

2

Todas las soluciones que he visto (en esta página y también en otros lugares) tienen un lado efecto que evitan en clics repetidos de velocidad rápida. Permite un clic por 500ms o similar. Esto puede estar bien en algunos casos, pero no por ejemplo. si tiene un tirador o botones de flecha para permitir el movimiento rápido de un elemento a otro.

La solución más sencilla es la siguiente:

$('#nozoom').on('touchstart', function(e) 
{ 
    fn_start(e); 
    e.preventDefault(); 
}); 

Esto exige fn_start() (la función de devolución de llamada real) cada vez que se inicia el tacto, pero impide entonces por defecto empinadas etc.

El ejemplo comparativo funcionamiento está aquí : http://jsbin.com/meluyevisi/1/. La caja verde impide, la caja roja lo permite.

Cuestiones relacionadas