Если вы хотите добавить немного интерактивности JavaScript на свои веб-страницы, возможно, вы слышали о делегировании событий JavaScript и думали, что это один из тех замысловатых шаблонов проектирования, о которых беспокоятся только хардкорные программисты JavaScript. Правда в том, что если вы уже знаете, как добавить обработчики событий JavaScript, это несложно реализовать.
События JavaScript — это основа всей интерактивности на веб-страницах (я имею в виду серьезную интерактивность, а не те изящные выпадающие меню CSS). В традиционной обработке событий вы добавляете или удаляете обработчики событий из каждого элемента по мере необходимости. Однако обработчики событий могут потенциально привести к утечкам памяти и снижению производительности — чем больше у вас есть, тем больше риск. Делегирование событий JavaScript — это простая техника, с помощью которой вы добавляете один обработчик событий в родительский элемент, чтобы избежать необходимости добавлять обработчики событий для нескольких дочерних элементов.
Как это работает?
При делегировании событий используются две часто пропускаемые функции событий JavaScript: всплывающее окно события и целевой элемент . Когда событие инициируется на элементе, например, щелчком мыши по кнопке, то же событие также запускается для всех предков этого элемента. Этот процесс известен как всплытие событий; событие всплывает от исходного элемента к вершине дерева DOM. Целевым элементом любого события является исходный элемент, кнопка в нашем примере, и он хранится в свойстве объекта события. Используя делегирование события, можно добавить обработчик события в элемент, дождаться, когда событие всплывет из дочернего элемента, и легко определить, из какого элемента произошло событие.
Как это поможет мне?
Представьте себе HTML-таблицу с 10 столбцами и 100 строками, в которой вы хотите, чтобы что-то происходило, когда пользователь щелкает ячейку таблицы. Например, однажды мне нужно было сделать каждую ячейку таблицы такого размера редактируемой при нажатии. Добавление обработчиков событий в каждую из 1000 ячеек было бы серьезной проблемой производительности и, возможно, источником утечек памяти при сбое браузера. Вместо этого, используя делегирование событий, вы добавляете только один обработчик событий к элементу table
, перехватываете событие click
и определяете, какая ячейка была нажата.
Как это выглядит в коде?
Код прост; нам нужно только беспокоиться об обнаружении целевого элемента. Допустим, у нас есть элемент table
с идентификатором « report
», и мы добавили в таблицу обработчик событий для события click
, которое editCell
функцию editCell
. Функция editCell
должна будет определить целевой элемент для события, которое всплыло в table
. Ожидая, что мы напишем несколько функций-обработчиков событий, которые будут нуждаться в этой функции, мы getEventTarget
ее в отдельную функцию с именем getEventTarget
:
function getEventTarget(e) { e = e || window.event; return e.target || e.srcElement; }
Переменная e
представляет объект события, и нам нужно только разбросать кросс-браузерный код, чтобы получить доступ и вернуть целевой элемент, сохраненный в свойстве srcElement
в Internet Explorer и свойстве target
в других браузерах.
Далее editCell
функция editCell
которая вызывает функцию getEventTarget
. Как только мы получим ссылку на целевой элемент, мы должны убедиться, что этот элемент именно тот, который мы ожидаем:
function editCell(e) { var target = getEventTarget(e); if(target.tagName.toLowerCase() === 'td') { // DO SOMETHING WITH THE CELL } }
В функции editCell
мы подтверждаем, что целевой элемент является ячейкой таблицы, проверяя его имя тега. Эта проверка может быть слишком упрощена; Что если это другой элемент внутри ячейки таблицы, который является целью события? Может потребоваться быстрая модификация, которая добавляет код для поиска родительского элемента td
. Что делать, если некоторые ячейки не должны быть редактируемыми? В этом случае мы можем добавить определенное имя класса в нередактируемую ячейку и проверить, что целевой элемент не имеет этого имени класса, прежде чем сделать его редактируемым. Доступно много вариантов, и вам просто нужно выбрать тот, который подходит вашему приложению.
Каковы плюсы и минусы?
Преимущества делегирования событий JavaScript:
- Существует меньше обработчиков событий для установки и хранения в памяти . Это большой; лучшая производительность и меньше сбоев.
- Нет необходимости повторно подключать обработчики после обновления DOM. Если содержимое вашей страницы генерируется динамически, например, с помощью Ajax, вам не нужно добавлять и удалять обработчики событий, поскольку элементы загружаются или выгружаются.
Потенциальные проблемы могут быть менее очевидными, но как только вы узнаете о них, их легко избежать:
- Существует риск, что ваш код управления событиями может стать узким местом в производительности, поэтому держите его как можно меньше.
- Не все события пузырьков. События
blur
,focus
,load
иunload
не всплывают, как другие события. К событиямblur
иfocus
можно получить доступ, используя фазу захвата (в браузерах, отличных от IE), а не фазу пузырьков, но это история для другого дня. - Вы должны быть осторожны при управлении событиями мыши. Если ваш код обрабатывает событие
mousemove
вы рискуете создать узкое место в производительности, потому что событиеmousemove
вызывается так часто. Событиеmouseout
имеет странное поведение, которым трудно управлять с делегированием события.
Резюме
Доступны примеры делегирования событий JavaScript, в которых используются основные библиотеки: jQuery , Prototype и Yahoo! Пользовательский интерфейс Вы также можете найти примеры, в которых вообще не используется библиотека, например, из блога Usable Type .
Делегирование событий — это удобный инструмент, который может быть в вашем наборе в случае необходимости и простой в реализации.