Что делает делегирование по сравнению с простым on('click',)?

В чем разница в производительности и обработке этих двух разных операторов jQuery:

  1. Номер один:

    $('#selector1, #selector2, .class1').on('click', function () { 
         //stuff
    });
    
  2. Номер два:

    $(document).on('click', '#selector1, #selector2, .class1', function () { 
         //stuff
    });
    

Я знаю, что один делает делегирование, а другой нет.

Но что это значит?

Разве оба не выполняют какое-то действие, когда вы нажимаете на '#selector1, #selector2, .class1'?

В конце концов, разве это не то же самое?


person Naftali aka Neal    schedule 14.11.2011    source источник
comment
Семантика, если вы спросите меня.   -  person Mech Software    schedule 14.11.2011
comment
Определенно НЕ семантика. Рекомендуется делегирование.   -  person Ryan Kinal    schedule 14.11.2011
comment
Это было хорошее чтение о live() против bind() против delegate() alfajango.com/blog/   -  person fehays    schedule 14.11.2011
comment
См. также канонический В чем разница между jQuery .live() и .on ()   -  person Charles    schedule 14.11.2011


Ответы (4)


Номер один перехватит событие click для элементов, которые существуют, когда вы выполняете этот оператор. Например, обработчик напрямую подключается к фактическим элементам, которые совпадают при выполнении этого вызова.

Number Two перехватит событие click в документе и при получении любого клика проверит, соответствует ли элемент, по которому фактически щелкнули, какому-либо из заданных селекторов, и если да, то запустит обработчик. Это делегирование события, а не прямое подключение.

Итак, это означает несколько вещей:

  1. Используя номер два, клики по элементам, которые вы добавите позже, вызовут обработчик; с номером один они не будут.
  2. Только всплывающие события, такие как click, работают с номером два (поскольку он основан на событии, поднимающем DOM до уровня документа).
  3. Если вы используете делегированный обработчик (номер два), а какой-то другой код перехватывает событие на фактическом элементе, а затем отменяет распространение (всплывание) события, делегированный обработчик его не увидит.
  4. Делегированная форма (номер два) должна сопоставлять элемент, по которому щелкнули (и, возможно, его предков), с селектором, когда происходит щелчок, что занимает ненулевое время. Не обязательно много времени, но больше, чем прямой обработчик (который не обязан этого делать). Если у вас много делегированных обработчиков одного и того же элемента (в данном случае документа), вы можете начать замечать.

Бывают случаи, когда лучше использовать обработчик с прямым подключением, а иногда лучше делегирование события (обычно с использованием чего-то более целенаправленного, чем document). Обычно разделительная линия между ними является оценочным вызовом, но, например, если вы хотите реагировать на щелчки по строкам таблицы, вам, вероятно, лучше перехватывать событие click для элемента table с помощью селектора tr, а не прикреплять click событие каждой отдельной строки таблицы, особенно если вы обновляете таблицу динамически. Принимая во внимание, что если у вас есть уникальная кнопка, о которой вы знаете, что она существует в DOM, когда вы подключаете свой обработчик, и вы хотите запустить определенную функцию при нажатии этой кнопки (но не чего-либо еще), прямой обработчик, вероятно, имеет больше смысла.

Вот пример (активная копия):

HTML:

<p>Click me</p>

JavaScript:

jQuery(function($) {

  $('p').on('click', function() {
    display("Directly-attached handler fired. Click this paragraph and note the difference in what happens compared to when you click the 'click me' paragraph.");
  });
  $(document).on('click', 'p', function() {
    display("Delegated handler fired.");
  });

  function display(msg) {
    $("<p>").html(msg).appendTo(document.body);
  }
});

Обратите внимание, что когда вы щелкаете абзац «щелкни меня», вы получаете два новых абзаца, добавленных в документ, один из которых является результатом первого вызова on, а другой — результатом второго. Но обратите внимание: если щелкнуть любой из этих двух новых абзацев, вы увидите только обработчик второго вызова on (делегированного), а не первого. Это потому, что эти абзацы не существовали, когда вы подключили первый обработчик.

person T.J. Crowder    schedule 14.11.2011
comment
Второй выполняет проверку во время выполнения, поэтому он медленнее. - person Raynos; 14.11.2011

  1. Метод on() прикрепляет обработчик событий для каждого из элементов, соответствующих объекту jQuery. Если вы передадите необязательный селектор методу on(), обработчик сработает только в том случае, если событие произошло в потомке этого элемента.

    Из-за этого в первом примере будет присоединено несколько обработчиков событий, поскольку объект jQuery содержит 3 элемента. Однако во втором примере будет присоединен один обработчик событий, который будет обрабатывать событие щелчка для всех '#selector1, #selector2, .class1'.

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

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

  2. Поскольку on() прикрепляет обработчики к каждому элементу, соответствующему объекту jQuery, вы не можете напрямую прикреплять обработчики к элементам, которых еще нет в DOM (например, если вы хотите добавить элементы программно через код или через AJAX). Именно здесь возможность предоставления селектора в качестве параметра для on() становится чрезвычайно полезной; это позволяет вам прикрепить обработчик событий к элементу, который в данный момент находится в DOM, но который будет обрабатывать события, которые срабатывают на элементах, которых еще нет в DOM (но которые соответствуют предоставленному вами селектору) .

    Иными словами, в первом примере jQuery прикрепляет обработчик событий ко всем элементам, которые соответствуют селектору #selector1, #selector2, .class1; и поэтому пропустит все элементы, которые еще не были зарегистрированы в DOM.

    С другой стороны, если вы используете второй пример, jQuery прикрепляет обработчик событий ко всем элементам, которые соответствуют селектору document (например, к одному элементу Document), и прикрепляет к нему обработчик, который сработает, если событие, которое он получает, возникло из элемент, соответствующий селектору #selector1, #selector2, .class1; это имеет то преимущество, что работает для всех будущих элементов #selector1, #selector2, .class1.

    Вы можете увидеть это в действии здесь; http://jsfiddle.net/kntR7/

  3. Поскольку число два привязано к document, любой элемент, который принимает обработчик того же события, получит обработчик раньше (поскольку document — это последнее место, которое получает обработчик через распространение события), поэтому, если он решит отменить событие, используя event.stopPropagation() или event.stopImmediatePropagation() обработчик никогда не будет достигнут.

    Вы можете увидеть это в действии здесь; http://jsfiddle.net/mkNyU/

person Matt    schedule 14.11.2011

Для тех, кто знаком с синтаксисом до версии 1.7, вот как можно использовать on:

//bind syntax
$(selector).on(event, callback);
$(selector).bind(event, callback);

//delegate syntax
$(parent).on(event, selector, callback);
$(selector).delegate(selector, event, callback);

//live syntax
$(document).on(event, selector, callback);
$(selector).live(event, callback);

Итак, ваша первая строка ($('#selector1, #selector2, .class1').on('click', function)) представляет собой формат bind для присоединения событий к существующим элементам.

Ваша вторая строка ($(document).on('click', '#selector1, #selector2, .class1', function)) представляет собой формат live для присоединения событий к любому элементу, который соответствует селектору, когда происходит событие, независимо от того, существуют ли элементы в dom во время привязки.

person zzzzBov    schedule 14.11.2011
comment
@Neal - я нашел этот ответ очень полезным (как и многие предыдущие пользователи jQuery), потому что я уже знал, что сделали .bind(), .delegate() и .live(), поэтому теперь я вижу, как можно использовать .on() для соответствия этому поведению. Итак, кто-то был знаком с тем, как до jQuery 1.7 делать что-то с .bind(), .delegate() и .live(), тогда это действительно отвечает на вопрос. Очевидно, что если бы вы не знали ни одной из предыдущих функций, то эта не была бы столь полезной, но в этой презентации есть некоторая аргументация и полезность. - person jfriend00; 14.11.2011

Первый связывает 3+ обработчика событий (по одному на каждый элемент), которые теряются при замене элементов. Первый потерпит неудачу, если элементы еще не существуют.

Второй привязывает 1 обработчик событий (один к document ), который никогда не будет потерян, если вы не удалите его явно. И как только здесь вызывается обработчик, событие уже распространилось на document. Каждый раз, когда вы щелкаете в любом месте страницы, jQuery внутренне проверяет, был ли он на каком-либо элементе, который соответствует предоставленному вами селектору, и запускает указанный вами обработчик, если он соответствует. Это только в том случае, если событие распространилось на document и не было остановлено на элементе более низкого уровня.

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

person Esailija    schedule 14.11.2011