Должны ли все события jquery быть привязаны к $(документу)?

Если это происходит от

Когда я впервые узнал jQuery, я обычно добавлял такие события:

$('.my-widget a').click(function() {
    $(this).toggleClass('active');
});

Узнав больше о скорости выбора и делегировании событий, я прочитал в нескольких местах, что "делегирование события jQuery сделает ваш код быстрее". Поэтому я начал писать код следующим образом:

$('.my-widget').on('click','a',function() {
    $(this).toggleClass('active');
});

Это был также рекомендуемый способ воспроизвести поведение устаревшего события .live(). Что важно для меня, так как многие мои сайты постоянно добавляют/удаляют виджетов. Вышеизложенное не ведет себя точно так же, как .live(), поскольку только элементы, добавленные в уже существующий контейнер ".my-widget", получат поведение. Если я динамически добавлю еще один блок html после запуска этого кода, эти элементы не получат связанных с ними событий. Вот так:

setTimeout(function() {
    $('body').append('<div class="my-widget"><a>Click does nothing</a></div>');
}, 1000);


Что я хочу достичь:

  • старое поведение .live()//означает добавление событий в еще не существующие элементы.
  • преимущества .on()
  • максимальная производительность для привязки событий
  • Простой способ управления событиями

Теперь я присоединяю все события вроде этого:

$(document).on('click.my-widget-namespace', '.my-widget a', function() {
    $(this).toggleClass('active');
});

Который, кажется, отвечает всем моим целям. (Да, по какой-то причине он медленнее в IE, не знаю, почему?) Это быстро, потому что только одно событие привязано к сингулярному элементу, а вторичный селектор оценивается только тогда, когда происходит событие (пожалуйста, исправьте меня, если это не так). Пространство имен является удивительным, поскольку упрощает переключение прослушивателя событий.

Мое решение/вопрос

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

Если вы прочитали все это, спасибо. Я ценю любые/все отзывы/идеи.

Предположения:

  • Использование jQuery, поддерживающего .on()//как минимум версию 1.7
  • Вы хотите, чтобы событие добавлялось к динамически добавленному контенту.

Показания/Примеры:

Ответ 1

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

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

Во-вторых, вы НЕ должны привязывать все делегированные события на уровне документа. Именно поэтому .live() был устаревшим, потому что это очень неэффективно, когда у вас много событий, связанных таким образом. Для делегированной обработки событий намного эффективнее связывать их с ближайшим родителем, который не является динамическим.

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

Здесь время, когда делегирование событий требуется или выгодно:

  • Когда объекты, в которые вы записываете события, динамически создаются/удаляются, и вы все равно хотите записывать на них события, не переустанавливая обработчики событий каждый раз при создании нового.
  • Когда у вас есть много объектов, которые все хотят точно такого же обработчика событий (где лоты по меньшей мере сотни). В этом случае во время установки может быть более эффективным связывать один делегированный обработчик событий, а не сотни или более прямых обработчиков событий. Обратите внимание: делегированная обработка событий всегда менее эффективна во время выполнения, чем прямые обработчики событий.
  • Когда вы пытаетесь захватить (на более высоком уровне в документе) события, которые происходят на любом элементе документа.
  • Когда ваш проект явно использует событие bubbling и stopPropagation(), чтобы решить некоторые проблемы или функции на вашей странице.

Чтобы понять это немного, нужно понять, как работают обработчики jQuery делегированных обработчиков событий. Когда вы вызываете что-то вроде этого:

$("#myParent").on('click', 'button.actionButton', myFn);

Он устанавливает общий обработчик событий jQuery в объекте #myParent. Когда событие кликается до этого делегированного обработчика событий, jQuery должен пройти список делегированных обработчиков событий, прикрепленных к этому объекту, и посмотреть, соответствует ли исходный элемент для события любому из селекторов в делегированных обработчиках событий.

Поскольку селекторы могут быть довольно вовлечены, это означает, что jQuery должен анализировать каждый селектор, а затем сравнивать его с характеристиками исходной цели события, чтобы увидеть, соответствует ли он каждому селектору. Это не дешевая операция. Это не имеет большого значения, если есть только один из них, но если вы поместили все свои селекторы в объект документа и были сотни селекторов, которые бы сравнивались с каждым событием с пузырьками, это может серьезно зависнуть от производительности обработки событий.

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


Итак, для достижения оптимальной производительности:

  • Используйте только делегированную обработку событий, когда она действительно предоставляет требуемую функцию или повышает производительность. Не всегда используйте его, потому что это легко, потому что, когда вам это действительно не нужно. Это на самом деле хуже работает во время отправки события, чем привязка прямого события.
  • Прикрепите делегированные обработчики событий к ближайшему родителю к источнику события, насколько это возможно. Если вы используете делегированную обработку событий, потому что у вас есть динамические элементы, для которых вы хотите записывать события, затем выберите ближайшего родителя, который сам по себе не является динамическим.
  • Используйте простые в использовании селектора для делегированных обработчиков событий. Если вы следовали за тем, как работает делегированная обработка событий, вы поймете, что делегированный обработчик событий нужно сравнивать с большим количеством объектов много раз, поэтому вы выбираете как можно эффективный селектор или добавляете простые классы к своим объектам, поэтому более простые селектора могут использоваться повысить производительность делегированной обработки событий.

Ответ 2

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

Когда вы должны использовать делегирование событий?

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

Почему вы не должны использовать делегирование событий?

  • Делегирование событий медленнее по сравнению с привязкой события непосредственно к элементу.
    • Он сравнивает целевой селектор на каждом попадающем пузыре, сравнение будет таким же дорогостоящим, насколько это сложно.
  • Никакой контроль над событием пузырится до тех пор, пока он не ударит по элементу, к которому он привязан.

PS: Даже для динамического содержимого вам не нужно использовать метод делегирования событий, если вы привязываете обработчик после того, как содержимое вставлено в DOM. (Если динамический контент добавляется не часто удаляется/повторно добавляется)

Ответ 3

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

https://gomakethings.com/why-event-delegation-is-a-better-way-to-listen-for-events-in-vanilla-js/

"Веб-производительность # Такое ощущение, что прослушивание каждого клика в документе будет вредно для производительности, но на самом деле это более эффективно, чем иметь кучу слушателей событий по отдельным элементам ".