web-dev-qa-db-ja.com

Safari iPad:ダブルタップでズームを防ぐ

Safari foriPadでサイトを作成しています。ダブルタップイベントのズームを防ぐ必要がありますが、2つの問題があります。

  • ダブルタップしてもイベントは生成されないため、「event.preventDefault();」を使用できません。
  • 一部の条件が満たされた場合にのみこれを行う必要があるため、タグ「<meta name = "viewport" content = "user-scalable = no">」を使用できません...これを行うと、ユーザーは私のページを拡大できなくなります。

これらの問題を解決するにはどうすればよいですか?

11
Nicolas

Mobile Safariは、javascriptondblclickイベントをサポートしていません。 Safariでは「ズーム」と解釈されます。

Raul Sanchezが潜在的な解決策を投稿しました: http://appcropolis.com/implementing-doubletap-on-iphones-and-ipads/

7
jim31415

これは私が同じ目的で書いた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);
7
ecmanaut

この変更されたコードを試してください。 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();
6
Abdul Hamid

@ecmanautのjavascriptソリューションを変更して、2つのことを実行しました。

  1. 私はmodernizrを使用しているので、htmlノードに.touch cssクラスを配置するので、ユーザーエージェント検出を使用する代わりにタッチスクリーンを検出できます。 「モダニズレス」のアプローチがあるかもしれませんが、私にはわかりません。
  2. それぞれの「クリック」を分けて別々に発生させます。1回クリックすると1回クリックし、ボタン/トリガーをすばやくクリックすると複数回カウントされます。
  3. いくつかのマイナーなコードフォーマットの変更、私は各変数を別々に定義することを好みます、これは他の何よりも「私」のものです、私はあなたがそれを元に戻すことができると思います、悪いことは何も起こりません。

私はこれらの変更がそれをより良くすると信じています、なぜならあなたは2,4,6,8の代わりにカウンター1,2,3,4をインクリメントすることができるからです

変更されたコードは次のとおりです。

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

このように、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ノードを使用できます。これ以上何もする必要はありません。この方法ですべてのイベントハンドラーをアタッチする必要があります。別の方法は試していませんが、この方法は完全に堅実に機能し、文字通り1秒間に10回画面をラップできます。ズームせず、クリック数を記録します(明らかに、1秒あたり10回ではありません。iPadはそれほど高速ではありません。つまり、ズームをトリガーすることはできません)。

Nozoomハンドラーを本体にアタッチしてから、すべてのイベントハンドラーを「.content」ノードにアタッチしているが、問題の特定のノードに委任しているため、これは機能すると思います。したがって、jqueryは前の最後の段階ですべてのハンドラーをキャッチします。イベントはbodyタグまでバブルアップします。

このソリューションの主な利点は、nodoubletapzoom()ハンドラーを本体に割り当てるだけでよく、要素ごとに1回ではなく、1回だけ実行するため、作業、労力、思考が大幅に削減されます。

これには、AJAXを使用してコンテンツを追加すると、ハンドラーが自動的に準備されて待機するという追加の利点があります。DIDNTが必要な場合は、このメソッドは機能せず、さらに調整する必要があります。

私はこのコードがipadで動作することを確認しました、それは実際には美しく、主要な解決策のために@ecmanautによくやった!!

** 5月26日土曜日に変更されました。これは、最小限の労力で完璧なソリューションと思われるものを見つけたためです。

5

私が(このページや他の場所で)見たすべての解決策には、高速の繰り返しクリックを防ぐという副作用があります。 500msなどごとに1回のクリックが可能です。これは場合によっては問題ありませんが、たとえば問題はありません。アイテムからアイテムへの高速移動を可能にするシューターまたは矢印ボタンがある場合。

最も簡単な解決策はこれです:

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

これにより、タッチが開始されるたびにfn_start()(実際のコールバック関数)が呼び出されますが、デフォルトのズームなどは防止されます。

実用的な比較例は次のとおりです: http://jsbin.com/meluyevisi/1/ 。緑のボックスは防止し、赤のボックスは許可します。

3
Timo Kähkönen

ビューポートを設定するだけでは必ずしも十分ではない場合があります。場合によっては、event.preventDefault();も呼び出す必要があります。タッチスタートハンドラー。

1
tim

受け入れられた「ダブルクリック」の答えは、私にとっては少し「肥大化」し、タイムスタンプを使用しています.....なぜですか?過度の「肥大化」のないこの単純な実装を見てください。

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
Codebeat