Safari iPad:防止双击放大

Posted

技术标签:

【中文标题】Safari iPad:防止双击放大【英文标题】:Safari iPad : prevent zoom on double-tap 【发布时间】:2011-03-07 10:33:22 【问题描述】:

我正在 Safari 上为 iPad 创建一个站点。我需要防止双击事件的缩放,但我有两个问题:

双击不会产生任何事件,所以我不能使用“event.preventDefault();” 我只有在满足某些条件时才需要这样做,所以我不能使用标签“<meta name = "viewport" content = "user-scalable = no">”...如果这样做,用户将永远无法放大我的页面。

我该如何解决这些问题?

【问题讨论】:

【参考方案1】:

Mobile Safari 不支持 javascript ondblclick 事件。 Safari 将其解释为“缩放”。

Raul Sanchez 发布了一个潜在的解决方案: http://appcropolis.com/implementing-doubletap-on-iphones-and-ipads/

【讨论】:

我确实用过这个解决方案...这个话题很详细,谢谢!对于访问者,主要思想如下:首先,捕捉“点击”事件。然后,如果在 500 毫秒之前抛出另一个“点击”事件:这是一个“双击”,所以如果你可以在此处停止该事件 -> 没有“双击”:) 请参阅链接以获取更多解释。 *** 上的答案不应只是指向外部站点的链接;请将解决方案的基本部分添加到此答案中。【参考方案2】:

这是我为相同目的编写的一个 jQuery 插件 - 有选择地禁用给定页面元素的双击缩放(在我的情况下,导航按钮用于翻页)我想响应每个点击(包括双击)作为正常的点击事件,没有 ios 的“触摸魔法”。

要使用它,只需在您关心的元素上运行$('.prev,.next').nodoubletapzoom(); 之类的东西。 (编辑:现在也忽略了捏)

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

【讨论】:

这可行,但有一个错误:多于两次点击。在触发被吞噬的点击后添加:$(this).data('lastTouch', 0);。没有它,当您三次点击时,您会获得四次点击(四次点击可能更多)。有了它,您可以在三次点击时点击三下,在四次点击时点击四次。这个想法是你可能有一个元素应该响应许多连续的点击(而不是因为任何原因被按住)。 此解决方案似乎可以防止所有重复点击,如果它们之间的延迟小于 500 毫秒。是否有可能允许点击例如。在 500 毫秒的时间范围内进行 5 次并且仍然阻止缩放?我需要一种在鼠标设备中重复点击的工作方式。 我找到了解决射手问题的简单方法:***.com/a/30744654/1691517。它不会“等待” 500 毫秒,直到允许新的点击,而是立即执行,但仍可防止不必要的点击缩放。【参考方案3】:

仅设置视口可能并不总是足够的 - 在某些情况下,您可能还需要调用 event.preventDefault(); 在 touchstart 处理程序上。

【讨论】:

【参考方案4】:

我修改了@ecmanaut 的 javascript 解决方案来做两件事。

    我使用modernizr,所以它会在html节点上放置一个.touch css类,所以我可以检测触摸屏而不是使用用户代理检测。也许有一种“无现代化”的方法,但我不知道。 我将每个“点击”分开,以便它们单独发生,如果您点击一次,它会点击一次,如果您快速点击按钮/触发器,它会计算多次。 一些小的代码格式更改,我更喜欢单独定义的每个 var 等,这更像是一个“我”的东西,我想你可以恢复它,不会发生任何不好的事情。

我相信这些修改会使它变得更好,因为您可以将计数器递增 1,2,3,4 而不是 2,4,6,8

这里是修改后的代码:

//  jQuery no-double-tap-zoom plugin
//  Triple-licensed: Public Domain, MIT and WTFPL license - share and enjoy!
//
//  chris.thomas@antimatter-studios.com: 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);

将 nodoubletapzoom() 应用到 body 标签,像这样

$("body").nodoubletapzoom();

你的html结构,应该是这样的

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

然后在您的 javascript 中,像这样绑定您的点击处理程序

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

您可以使用任何 jquery 事件处理程序和任何 dom 节点。现在你不需要做更多的事情,你必须以这种方式附加所有的事件处理程序,我没有尝试过另一种方式,但这种方式绝对可靠,你可以每秒敲击屏幕 10 次并且它不会缩放并记录点击(显然不是每秒 10 次,ipad 没那么快,我的意思是,您无法触发缩放)

我认为这是可行的,因为您将 nozoom 处理程序附加到正文,然后将所有事件处理程序附加到“.content”节点,但委托给有问题的特定节点,因此 jquery 捕获所有处理程序活动前的最后阶段会冒泡到 body 标签。

此解决方案的主要好处是您只需将 nodoubletapzoom() 处理程序分配给主体,您只需执行一次,而不是为每个元素执行一次,因此获得所需的工作、努力和思考要少得多事情做完了。

这还有一个额外的好处,如果你使用 AJAX 添加内容,它们会自动让处理程序准备好并等待,我想如果你不想要,那么这个方法对你不起作用,你必须调整更多。

我已验证此代码可在 ipad 上运行,实际上它很漂亮,@ecmanaut 的主要解决方案做得很好!

** 于 5 月 26 日星期六修改,因为我发现似乎是一个完美的解决方案,而且工作量极少

【讨论】:

【参考方案5】:

接受的“双击”答案对我来说有点“臃肿”并使用时间戳......为什么?看看这个没有过多“臃肿”的简单实现。

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

用法:

simulateDblClickTouchEvent($('#example'));

or 

simulateDblClickTouchEvent($('.example'));

函数在事件是否绑定时返回真或假。

要防止缩放和滚动,请执行以下操作:

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;

使用 CSS 也很容易避免缩放:

body *  -webkit-user-select:none; 
= 效率不高,但试试吧,效果很好。

干杯!

【讨论】:

【参考方案6】:

试试这个修改后的代码。它应该适用于 android 和 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);

然后将 nodoubletapzoom() 应用于 body 标签

$("body").nodoubletapzoom();

【讨论】:

谢谢!我举了一个例子:jsbin.com/dihoxedika/1。 ecmanauts 代码中的问题是$(this).trigger('click').trigger('click')。当我用e.target 替换this 并删除第二个触发器时,它开始在Android Chrome 中工作。问题是无法快速重复点击。【参考方案7】:

我看到的所有解决方案(在此页面和其他地方)都有一个副作用,它们可以防止快速重复点击。允许每 500 毫秒或类似的单击一次。这在某些情况下可以,但不是例如。如果你有一个射击或箭头按钮来允许快速从一个项目移动到另一个项目。

最简单的解决办法是这样的:

$('#nozoom').on('touchstart', function(e)

  fn_start(e);
  e.preventDefault();
);

这会在每次触摸开始时调用fn_start()(实际的回调函数),但会阻止默认缩放等。

工作比较示例在这里:http://jsbin.com/meluyevisi/1/。 绿框阻止,红框允许。

【讨论】:

【参考方案8】:

如果有人需要没有 jQuery 的解决方案,我发现这个 (https://exceptionshub.com/disable-double-tap-zoom-option-in-browser-on-touch-devices.html) 工作得很好。函数期望和事件对象作为参数:

function preventZoom(e) 
  var t2 = e.timeStamp;
  var t1 = e.currentTarget.dataset.lastTouch || t2;
  var dt = t2 - t1;
  var fingers = e.touches ? e.touches.length : 0;
  e.currentTarget.dataset.lastTouch = t2;

  if (!dt || dt > 500 || fingers > 1) return; // not double-tap

  e.preventDefault();
  e.target.click();

Angular 10 示例:

<!— Template —>

<span (click)="clicked($event)">Click me</span>
Component

clicked(event) 
  this.preventZoom(event);
  // your code


preventZoom(e) 
  var t2 = e.timeStamp;
  var t1 = e.currentTarget.dataset.lastTouch || t2;
  var dt = t2 - t1;
  var fingers = e.touches?.length;
  e.currentTarget.dataset.lastTouch = t2;

  if (!dt || dt > 500 || fingers > 1) return; // not double-tap

  e.preventDefault();
  e.target.click();

【讨论】:

以上是关于Safari iPad:防止双击放大的主要内容,如果未能解决你的问题,请参考以下文章

从 iPad 上的列表中卸载页面时,如何防止 mobile-safari 跳转?

防止放大Phonegap + JQuery Mobile

如何防止在 Safari 移动浏览器上捏缩放(滚动)?

如何防止 iOS Safari 输入标签中的自动大写?

防止 UIWebview 上的捏缩放和双击缩放

键盘出现时防止用户界面移动