Откуда это идет
Когда я впервые изучил 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 всегда должны быть связаны с $ (document).
Есть ли причина, по которой вы не захотите этого делать?
Может ли это считаться лучшей практикой? Если нет, то почему?
Если вы все прочитали, спасибо. Я ценю любые / все отзывы / идеи.
Предположения:
- Используя jQuery, который поддерживает
.on()
// как минимум версию 1.7 - Вы хотите, чтобы событие было добавлено в динамически добавляемый контент
Показания / Примеры:
Ответы:
Нет - вы НЕ должны связывать все делегированные обработчики событий с
document
объектом. Это, вероятно, худший сценарий, который вы могли бы создать.Во-первых, делегирование событий не всегда делает ваш код быстрее. В некоторых случаях это выгодно, а в некоторых - нет. Вы должны использовать делегирование событий, когда вам действительно нужно делегирование событий и когда вы получаете от этого пользу. В противном случае вы должны привязывать обработчики событий непосредственно к объектам, где происходит событие, поскольку это обычно будет более эффективным.
Во-вторых, вы НЕ должны связывать все делегированные события на уровне документа. Именно поэтому это
.live()
было объявлено устаревшим, потому что это очень неэффективно, когда у вас много событий, связанных таким образом. Для делегированной обработки событий НАМНОГО более эффективно связать их с ближайшим родителем, который не является динамическим.В-третьих, не все мероприятия работают или все проблемы могут быть решены с делегированием. Например, если вы хотите перехватить ключевые события в элементе управления вводом и заблокировать ввод недопустимых ключей в элемент управления вводом, вы не сможете сделать это с обработкой делегированных событий, потому что к тому времени, когда событие переходит в делегированный обработчик, оно уже имеет обработан входным управлением, и уже слишком поздно влиять на это поведение.
Вот случаи, когда делегирование события требуется или выгодно:
Чтобы понять это немного больше, нужно понять, как работают делегированные обработчики событий jQuery. Когда вы звоните что-то вроде этого:
Он устанавливает универсальный обработчик событий jQuery на
#myParent
объект. Когда событие click вспыхивает до этого обработчика делегированных событий, jQuery должен просмотреть список обработчиков делегированных событий, прикрепленных к этому объекту, и посмотреть, соответствует ли исходный элемент для события любому из селекторов в обработчиках делегированных событий.Поскольку селекторы могут быть задействованы в достаточной степени, это означает, что jQuery должен проанализировать каждый селектор и затем сравнить его с характеристиками исходного целевого события, чтобы увидеть, соответствует ли он каждому селектору. Это не дешевая операция. Нет ничего страшного, если есть только один из них, но если вы поместите все свои селекторы в объект документа и сотни селекторов будут сравниваться с каждым отдельным всплывающим событием, это может серьезно снизить производительность обработки событий.
По этой причине вы хотите настроить делегированные обработчики событий так, чтобы делегированный обработчик событий был как можно ближе к целевому объекту. Это означает, что через каждый делегированный обработчик событий будет проходить меньше событий, что повышает производительность. Помещение всех делегированных событий в объект документа является наихудшей возможной производительностью, поскольку все всплывающие события должны проходить через все делегированные обработчики событий и оцениваться для всех возможных делегированных селекторов событий. Именно поэтому
.live()
не рекомендуется, потому что это то, что.live()
сделал, и это оказалось очень неэффективным.Итак, для достижения оптимизированной производительности:
источник
$(document).on('click', '[myCustomAttr]', function () { ... });
?document
, или связываются с более конкретными выборов наpage:load
и UNBIND этих событий наpage:after-remove
? ХмммДелегирование событий - это метод написания ваших обработчиков до того, как элемент действительно существует в DOM. Этот метод имеет свои недостатки и должен использоваться только при наличии таких требований.
Когда следует использовать делегирование событий?
Почему вы не должны использовать делегирование событий?
PS: даже для динамического содержимого вам не нужно использовать метод делегирования событий, если вы привязываете обработчик после того, как содержимое вставлено в DOM. (Если динамический контент добавляется не часто удаляется / повторно добавляется)
источник
Судя по всему, делегирование событий сейчас действительно рекомендуется. по крайней мере, для ванили JS.
https://gomakethings.com/why-event-delegation-is-a-better-way-to-listen-for-events-in-vanilla-js/
«Производительность в Интернете. Такое ощущение, что прослушивание каждого клика в документе может сказаться на производительности, но на самом деле это более производительно, чем иметь кучу слушателей событий по отдельным элементам».
источник
Я хотел бы добавить некоторые замечания и контраргументы к ответу jfriend00. (в основном только мои мнения, основанные на моем чувстве кишки)
Хотя это правда, что производительность может быть немного лучше, если вы собираетесь регистрировать и регистрировать только один элемент, я считаю, что это не сравнится с преимуществами масштабируемости, которые дает делегирование. Я также считаю, что браузеры будут (и будут) обрабатывать это все более и более эффективно, хотя у меня нет никаких доказательств этого. На мой взгляд, делегирование событий - это путь!
Я вроде согласен с этим. Если вы на 100% уверены, что событие произойдет только внутри контейнера, имеет смысл связать событие с этим контейнером, но я бы все же поспорил с тем, чтобы связывать события с инициирующим элементом напрямую.
Это просто неправда. Пожалуйста, смотрите этот codePen: https://codepen.io/pwkip/pen/jObGmjq
Он показывает, как вы можете запретить пользователю печатать, зарегистрировав событие нажатия клавиши в документе.
Я хотел бы ответить с этой цитатой из https://ehsangazar.com/optimizing-javascript-event-listeners-for-performance-e28406ad406c
Event delegation promotes binding as few DOM event handlers as possible, since each event handler requires memory. For example, let’s say that we have an HTML unordered list we want to bind event handlers to. Instead of binding a click event handler for each list item (which may be hundreds for all we know), we bind one click handler to the parent unordered list itself.
Кроме того, поиск в Google
performance cost of event delegation google
возвращает больше результатов в пользу делегирования событий.Где это задокументировано? Если это так, то jQuery, похоже, обрабатывает делегирование очень неэффективным образом, и тогда мои контраргументы должны применяться только к vanilla JS.
Тем не менее: я хотел бы найти официальный источник в поддержку этого утверждения.
:: РЕДАКТИРОВАТЬ ::
Похоже, что jQuery действительно делает всплывающее событие очень неэффективным способом (потому что они поддерживают IE8) https://api.jquery.com/on/#event-performance
Поэтому большинство моих аргументов здесь справедливы только для vanilla JS и современных браузеров.
источник