Direct vs. Delegated - jQuery.on()

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

Когда предоставляется selector, обработчик события называется делегированным. Обработчик не вызывается, когда событие происходит непосредственно на связанном элементе, но только для потомков (внутренних элементов), соответствующих селектору. jQuery создает пузырьки события от целевого объекта до элемента, к которому прикреплен обработчик (т.е. самого внутреннего к внешнему элементу), и запускает обработчик для любых элементов вдоль этого пути, соответствующих селектору.

Что это значит, "запускает обработчик для любых элементов"? Я сделал тестовую страницу , чтобы поэкспериментировать с этой концепцией. Но обе следующие конструкции приводят к такому же поведению:

$("div#target span.green").on("click", function() {
   alert($(this).attr("class") + " is clicked");
});

или,

$("div#target").on("click", "span.green", function() {
   alert($(this).attr("class") + " is clicked");
});

Может быть, кто-то может обратиться к другому примеру, чтобы прояснить этот момент? Спасибо.

Ответ 1

Случай 1 (прямой):

$("div#target span.green").on("click", function() {...});

== Эй! Я хочу, чтобы каждый span.green внутри цели div # слушал: когда вы нажимаете, делайте X.

Случай 2 (делегированный):

$("div#target").on("click", "span.green", function() {...});

== Эй, цель div #! Когда какой-либо из ваших дочерних элементов, которые являются "span.green", нужно щелкнуть, сделайте X с ними.

Другими словами...

В случае 1 каждому из этих интервалов были предоставлены индивидуальные инструкции. Если создаются новые промежутки, они не будут слышать инструкцию и не будут реагировать на клики. Каждый диапазон несет прямую ответственность за собственные события.

В случае 2 только инструкция была предоставлена ​​только контейнеру; он отвечает за уведомление кликов от имени своих дочерних элементов. Работа событий ловли была делегирована. Это также означает, что инструкция будет выполняться для дочерних элементов, которые создаются в будущем.

Ответ 2

Первый способ, $("div#target span.green").on(), привязывает обработчик кликов непосредственно к диапазону (диапазонам), которые соответствуют селектору в момент выполнения этого кода. Это означает, что если другие промежутки будут добавлены позже (или их класс изменится, чтобы соответствовать), они пропустили и не будут иметь обработчик кликов. Это также означает, что если вы позже удалите "зеленый" класс из одного из прогонов, его обработчик клика будет продолжать работать - jQuery не отслеживает, как был назначен обработчик, и проверьте, соответствует ли селектор.

Второй способ, $("div#target").on(), привязывает обработчик кликов к div (s), которые соответствуют (опять же, это против тех, которые соответствуют в тот момент), но когда щелчок происходит где-то в div, функция обработчика будет запускается только в том случае, если щелчок произошел не только в div, но и в дочернем элементе, соответствующем селектору во втором параметре, на .on(), "span.green". Сделано так, что не имеет значения, когда эти дочерние промежутки были созданы, нажатие на них по-прежнему будет выполнять обработчик.

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

Ответ 3

Объяснение N3dst4 отлично. Исходя из этого, мы можем предположить, что все дочерние элементы находятся внутри тела, поэтому нам нужно использовать только это:

$('body').on('click', '.element', function(){
    alert('It works!')
});

Он работает с прямым или делегированным событием.

Ответ 4

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

  • Связанный означает, что осталось от .on.
  • Выбранный относится ко второму аргументу .on().

Делегирование не работает как .find(), выбирая подмножество связанных элементов. Селектор применяется только к строгим дочерним элементам.

$("span.green").on("click", ...

сильно отличается от

$("span").on("click", ".green", ...

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

ИЗМЕНИТЬ

Контрольный список того, почему делегированный .on не работает

Трудные причины, по которым $('.bound').on('event', '.selected', some_function) может не работать:

  • Связанный элемент не постоянный. Он был создан после вызова .on()
  • Выбранный элемент не является надлежащим дочерним связанного элемента. Это тот же самый элемент.
  • Выбранный элемент предотвратил пузырь события связанного элемента, вызвав .stopPropagation().

(Опущение менее сложных причин, таких как селектор с ошибками.)

Ответ 5

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

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

Для получения дополнительной информации и полного сравнения - http://maciejsikora.com/standard-events-vs-event-delegation/

Использование всегда делегированных обработчиков, которые, как я вижу, очень модно, не очень правильно, многие программисты используют его, потому что "он должен использоваться", но правда в том, что обработчики прямых событий лучше подходят для какой-либо ситуации и выбора, который должен использовать метод поддерживаться знаниями о различиях.