На этом шаге мы рассмотрим пример делегирования событий.
Всплытие события не всегда является помехой, довольно часто его можно использовать с немалой выгодой. Один из приемов, использующих всплытие события, называется делегированием события. С его помощью можно задействовать обработчик событий одного элемента для обработки событий множества элементов.
В нашем примере имеются всего три элемента <div class="button">, к которым подключаются обработчики события click. Но как быть, если элементов намного больше? Такая ситуация встречается намного чаще, чем может показаться. Представим, например, большую таблицу, где каждая строка содержит интерактивный элемент, для взаимодействия с которым требуется определить обработчик события click. Механизм неявной итерации позволяет легко присоединить обработчики событий ко всем таким элементам, но производительность при этом может пострадать, потому что внутренняя реализация библиотеки jQuery все равно выполняет цикл и для поддержки всех обработчиков потребуется большой объем памяти.
Вместо этого мы можем присвоить один обработчик события click родительскому элементу DOM. Вследствие процесса всплытия событие click в конечном итоге достигнет родительского элемента, и мы получим возможность обработать его.
Для примера применим эту методику к нашему переключателю стилей (невзирая на то, что малое число элементов не требует этого). Как отмечалось выше, для определения, какой элемент находился под указателем мыши в момент щелчка, можно использовать свойство event.target.
$(document).ready(function() { $('#switcher').click(function(event) { if ($(event.target).is('.button')) { $('body').removeClass(); if (event.target.id == 'switcher-narrow') { $('body').addClass('narrow'); } else if (event.target.id == 'switcher-large') { $('body').addClass('large'); } $('#switcher .button').removeClass('selected'); $(event.target).addClass('selected'); event.stopPropagation(); } }); $('#switcher').click(function() { $('#switcher .button').toggleClass('hidden'); }); });
Рис.1. Пример делегирования события
Полный текст этого примера можно взять здесь.Здесь мы использовали новый метод с именем .is(). Он принимает селекторные выражения, которые мы рассматривали в предыдущих шагах, и проверяет соответствие селектору текущего объекта jQuery. Если хотя бы один элемент множества соответствует селектору, метод .is() возвращает значение true. В данном случае выражение $(event.target). is('button') проверяет, имеет ли элемент, на котором был выполнен щелчок, класс button. Если проверка дает положительный результат, выполняется тот же программный код, что и прежде, за одним важным исключением: теперь ключевое слово this ссылается на элемент <div id="switcher">, поэтому всякий раз, когда требуется выяснить, на какой кнопке произошел щелчок, необходимо использовать свойство event.target.
Однако такая реализация имеет один не предусмотренный побочный эффект. Теперь щелчок на кнопке будет приводить к сворачиванию переключателя, как это происходило ранее, до того как был добавлен вызов метода .stopPropagation(). Обработчик, управляющий видимостью переключателя, сейчас подключен к тому же элементу, что и обработчик для кнопок, поэтому остановка распространения события не предотвращает сворачивание переключателя. Чтобы обойти эту проблему, можно удалить вызов .stopPropagation() и добавить еще одну проверку
$(document).ready(function() { $('#switcher').click(function(event) { if (!$(event.target).is('.button')) { $('#switcher .button').toggleClass('hidden'); } }); }); $(document).ready(function() { $('#switcher').click(function(event) { if ($(event.target).is('.button')) { $('body').removeClass(); if (event.target.id == 'switcher-narrow') { $('body').addClass('narrow'); } else if (event.target.id == 'switcher-large') { $('body').addClass('large'); } $('#switcher .button').removeClass('selected'); $(event.target).addClass('selected'); } }); });
Рис.2. Исправленный пример делегирования события
Полный текст этого примера можно взять здесь.Для данного случая этот пример слишком сложен, но с ростом числа элементов, к которым требуется подключить обработчики событий, делегирование событий становится более предпочтительным приемом.
На следующем шаге мы рассмотрим удаление обработчика события.