Safari iPad: 如何防止双击放大页面?

12

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

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

如何解决这些问题?

8个回答

7
这是我为同样目的编写的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);

这个代码可以运行,但有一个bug:多于两次的点击。在触发被吞噬的点击后添加以下代码:$(this).data('lastTouch', 0);。如果没有它,当你三次点击时会得到四次点击(四次或更多)。有了它,三次点击会得到三次点击,四次点击会得到四次点击。这个想法是你可能有一个元素需要响应许多连续的点击(而不是被按住,出于任何原因)。 - Radu C
这个解决方案似乎可以防止所有重复点击,如果它们之间的延迟小于500毫秒。是否有可能在500毫秒的时间范围内允许点击5次,并仍然防止缩放?我需要一种方法来处理鼠标设备中的重复点击。 - Timo Kähkönen
我找到了一个解决射击游戏问题的简单方法:https://dev59.com/6nA75IYBdhLWcg3wy8Qi#30744654。它不会“等待”500毫秒才允许新的点击,而是立即执行,但仍然可以防止意外的双击缩放。 - Timo Kähkönen

6

尝试使用这个修改后的代码,它应该适用于安卓和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);

然后在body标签上应用nodoubletapzoom()函数。
$("body").nodoubletapzoom();


6

2
我确实使用过这个解决方案... 这个主题真的很详细,谢谢!对于访问者来说,主要思路如下:首先,捕获一个“tap”事件。然后,如果在500毫秒内抛出另一个“tap”事件:这就是“double-tap”,所以如果你能在这里停止事件 -> 没有“double tap” :) 请查看链接获取更多解释。 - Nicolas
在 StackOverflow 上的答案不应该只是一个指向外部网站的链接;请将解决方案的关键部分添加到这个答案中。 - Thomas

5
我修改了@ecmanaut的JavaScript解决方案,做了两件事情。
  1. 我使用了modernizr,这样它会在html节点上放置一个.touch css类,所以我可以检测触摸屏幕而不是使用用户代理检测。也许有一种“无modernizr”的方法,但我不知道。
  2. 我将每个“click”分开,使它们分别发生,如果您单击一次,它将点击一次,如果您快速点击按钮/触发器,它将计数多次。
  3. 进行了一些小的代码格式更改,我喜欢每个变量单独定义等,这更多是我的个人偏好,我想你可以恢复原样,不会发生任何不好的事情。
我相信这些修改使它更好,因为您可以将计数器递增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处理程序附加到body上,然后将所有事件处理程序附加到".content"节点,但委托给特定的节点,因此jQuery在事件冒泡到body标签之前捕获所有处理程序。
这种解决方案的主要好处是您只需要将nodoubletapzoom()处理程序分配给body,只需执行一次,而不是为每个元素都执行一次,因此需要的工作量、精力和思考量要少得多。
这还有一个额外的好处,如果您使用AJAX添加内容,它们自动具有准备等待的处理程序。我想如果您不想要这个功能,那么这种方法就不适用于您,您需要进行更多的调整。
我已经验证了这段代码在iPad上的有效性,实际上非常美妙。@ecmanaut的主要解决方案非常出色!
**由于我发现了一种完美的解决方案,因此在5月26日星期六进行了修改,而且几乎没有任何努力。

4
我见过的所有解决方案(此页面和其他地方)都有一个副作用,即它们防止快速重复点击。只允许每500毫秒或类似间隔点击一次。这在某些情况下可能是可以接受的,但如果您有射手或箭头按钮以允许快速移动从项目到项目等,就不适用了。
最简单的解决方案如下:
$('#nozoom').on('touchstart', function(e)
{
  fn_start(e);
  e.preventDefault();
});

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

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


1

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


0

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

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

当事件被绑定或未被绑定时,函数返回true或false。

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

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; }
  • = 不是很高效,但尝试一下,它的表现非常好。

干杯!


0
如果有人需要一个不需要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();
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接