$ (document).onx обработчик кликов и стандартный обработчик кликов ведут себя по-разному на iOS

Я обычно связываю обработчики кликов с помощью формы,

$(document).on('click', 'element', function() { ... });

чтобы избежать проблем с загрузкой элементов позже. Это корректно работало на настольных браузерах (и Chrome emulating iPhone), но на реальном iPhone это не сработало (и я попробовал решения, например 'cursor: pointer;')

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

$('element').click(function() { ... });

и он начал работать. Почему эти два метода применения обработчика кликов работают по-разному на iOS?

Ответ 1

Я посмотрел исходный код jquery, и они одинаковы (оба .click и on('click') используют ту же функцию, что и .on.

.click

jQuery.each( ( "blur focus focusin focusout resize scroll click dblclick " +
    "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " +
    "change select submit keydown keypress keyup contextmenu" ).split( " " ),
    function( i, name ) {

    // Handle event binding
    jQuery.fn[ name ] = function( data, fn ) {
        return arguments.length > 0 ?
            this.on( name, null, data, fn ) :
            this.trigger( name );
    };
} );

как вы можете видеть, $.click в конечном итоге вызовет .on (или .trigger, если нет аргументов, которые не являются вашим случаем)

Ответ 2

Я думаю, что это происходит из-за задержки в 300 мс для мобильных браузеров.

Согласно Google:

... мобильные браузеры будут ждать примерно 300 мс с момента, когда вы нажимаете кнопку, чтобы запустить событие click. Причиной этого является что браузер ожидает, действительно ли вы выполняете двойное нажатие.

Я столкнулся с одной и той же проблемой для одного из моих клиентских проектов, и для этого я использовал https://github.com/ftlabs/fastclick библиотеку для устранения задержки 300 мс между физическим нажмите и включите событие клика в мобильных браузерах.

Вы также можете попробовать https://github.com/dave1010/jquery-fast-click

В том же проекте я также столкнулся с проблемой двойного касания для выпадающих меню, а также из-за задержки в 300 мс.

Проблема с двойным нажатием появлялась в браузерах/устройствах Android, поэтому я обнаружил пользовательский агент и применил специальную функцию для обработки этой проблемы, которая может быть вам полезна.

<?php 
 if (user_agent() == 'android') {
    $handleClick = "onclick=\"checkClicks('$base_url/index.php')\"";
    $homePage = "#";
} else {
    $handleClick = " ";
    $homePage = "index.php";
}
?>

<!--//Script to Handle menu for mobile devices-->
<script type="text/javascript">
//handle 300ms delay click in android devices
var clicks = 0;
function checkClicks(e) {
    clicks = clicks + 1;
    if (clicks == 2) {
        window.location = e;
    } else {
        //do nothing
    }
}
</script>

Вы также можете попробовать некоторые доступные плагины, чтобы справиться с этой проблемой, если вы сталкиваетесь.

https://github.com/dachcom-digital/jquery-doubleTapToGo

https://github.com/zenopopovici/DoubleTapToGo

Это может быть полезно и вам.

Edited

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

Это возможно, потому что большинство событий DOM пузыряют дерево из точки происхождения. Если вы нажмете на элемент #id, генерируется событие клика, которое будет всплывать через все элементы-предки (примечание стороны: на самом деле есть фаза до этого, называемая "фазой захвата", когда событие спускается по дереву к цели). Вы можете зафиксировать событие для любого из этих предков.

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

Делегируя обработчик событий, вы можете убедиться, что он выполняется для элементов, которые не существовали в DOM во время привязки. Если ваш #id-элемент был создан после второго примера, ваш обработчик никогда не выполнит. Связываясь с элементом, который, как вы знаете, определенно находится в DOM во время выполнения, вы гарантируете, что ваш обработчик фактически будет привязан к чему-то и может быть выполнен по мере необходимости позже.

Вероятно, он не работает из-за одного из:

  • Не использовать последнюю версию jQuery
  • Не заверяйте свой код внутри готового документа DOM
  • или вы делаете что-то, что заставляет событие не пузыриться до слушателя в документе.

Чтобы захватить события на элементах, которые создаются ПОСЛЕ объявления ваших прослушивателей событий, вы должны привязать к родительскому элементу или элементу выше в иерархии.

Например:

$(document).ready(function() {
    // This WILL work because we are listening on the 'document', 
    // for a click on an element with an ID of #test-element
    $(document).on("click","#test-element",function() {
        alert("click bound to document listening for #test-element");
    });

    // This will NOT work because there is no '#test-element' ... yet
    $("#test-element").on("click",function() {
        alert("click bound directly to #test-element");
    });

    // Create the dynamic element '#test-element'
    $('body').append('<div id="test-element">Click mee</div>');
});

В этом примере будет срабатывать только предупреждение "привязано к документу".

JSFiddle с jQuery 1.9.1