Safari iPad: предотвратите увеличение двойного касания

Я создаю сайт на Safari для iPad. Мне нужно предотвратить увеличение двойного нажатия, но у меня есть две проблемы:

  • двойное нажатие не генерирует никаких событий, поэтому я не могу использовать "event.preventDefault();"
  • Мне нужно сделать это только при выполнении некоторых условий, поэтому я не могу использовать тег "<meta name = "viewport" content = "user-scalable = no">"... Если бы я это сделал, пользователи никогда не смогли бы увеличить мою страницу.

Как я могу исправить эти проблемы?

Ответ 2

Здесь плагин jQuery, который я написал для этой же цели, - выборочное отключение масштабирования двойного касания по заданным элементам страницы (в моем случае, кнопки навигации для переворачивания страниц). Я хочу реагировать на каждое нажатие (включая двойное нажатие) в качестве нормальное событие click, без 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);

Ответ 3

попробуйте этот модифицированный код. Он должен работать как для устройств 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();

Ответ 4

Я изменил решение @ecmanaut javascript, чтобы сделать две вещи.

  • Я использую modernizr, поэтому он поместит класс .touch css в html node, поэтому я могу обнаружить сенсорные экраны вместо использования обнаружения пользовательского агента. Возможно, есть подход "модерн-менее", но я этого не знаю.
  • Я разделяю каждый "click", чтобы они происходили отдельно, если вы нажмете один раз, он щелкнет один раз, если вы быстро нажмете кнопку/триггер, он будет посчитать несколько раз.
  • некоторые незначительные изменения форматирования кода, я предпочитаю, чтобы каждый 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!
//
//  [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 node. теперь вам не нужно ничего делать, вы должны приложить все свои обработчики событий таким образом, я не пробовал по-другому, но этот способ работает абсолютно твердо, вы можете буквально разорвать экран 10 раз в секунду и он не масштабирует и не регистрирует клики (очевидно, не 10 в секунду, ipad не так быстро, я имею в виду, что вы не можете активировать масштабирование)

Я думаю, что это работает, потому что вы прикрепляете обработчик nozoom к телу, а затем привязываете все обработчики событий к ".content" node, но делегируете конкретный node, поэтому jquery ловит все обработчики на последнем этапе перед событием будут пузыриться до тега тела.

Основное преимущество этого решения состоит в том, что вам нужно назначить обработчик nodoubletapzoom() для тела, вы делаете его только один раз, а не один раз для каждого элемента, поэтому для работы требуется гораздо меньше усилий, усилий и мышления для получения все сделано.

у этого есть дополнительное преимущество в том, что если вы добавляете контент с помощью AJAX, у них автоматически будут готовые и ожидающие обработчики, я полагаю, если вы DIDNT хотите это, то этот метод не будет работать для вас, и вам придется настроить это больше.

Я проверил, что этот код работает на ipad, он красив на самом деле, хорошо сделан для @ecmanaut для основного решения!

** Изменено в субботу 26 мая, потому что я нашел то, что кажется идеальным решением с абсолютно минимальными усилиями.

Ответ 5

Все решения, которые я видел (на этой странице, а также в других местах), имеют побочный эффект, который они предотвращают при быстрых повторных кликах. Позволяет использовать один клик на 500 мс или аналогичный. В некоторых случаях это может быть хорошо, но не напр. если у вас есть стрелок или кнопки со стрелками, позволяющие быстро перемещаться от предмета к предмету.

Самое простое решение:

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

Это вызывает fn_start() (фактическая функция обратного вызова) каждый раз при запуске касания, но предотвращает масштабирование по умолчанию и т.д.

Рабочий сравнительный пример приведен здесь: http://jsbin.com/meluyevisi/1/. Зеленая коробка предотвращает, разрешает красное поле.

Ответ 6

просто установка видового экрана может быть не всегда достаточной - в некоторых случаях вам, возможно, придется также позвонить   event.preventDefault(); на обработчике touchstart.

Ответ 7

Принятый ответ "двойной щелчок" для меня немного "раздутый" и использование отметки времени..... почему? Посмотрите на эту простую реализацию без чрезмерного "раздувания".

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; }
  • = неэффективно, но попробуйте, он отлично работает.

Ура!