Способы добавления обработчиков в сравнении

В статье приводится сравнение способов добавления обработчиков через on(click), addEventListener и attachEvent.

Рассмотрены особенности, плюсы и минусы разных способов.

Считается, что вы знакомы с основными свойствами объекта события и порядком их обработки.

Добавление через on(имя события)

Самый универсальный метод. У него есть, пожалуй, только один существенный недостаток: можно повесить лишь один обработчик.

Кроме того, есть глюк с iframe: в Firefox не будет работать обработчик, назначенный так:

iframeElement.onclick = function(event) { .... }

Но будет прекрасно работать addEventListener:

iframeElement.addEventListener( "click", ... )
  1. Полная кросс-браузерность
  2. Только один обработчик на событие
  3. Глюк с iframe в браузерах от Mozilla

Специальные методы

Методы attachEvent/addEventListener имеют ряд общих недостатков.

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

На текущий момент (март 2010) addEventListener сохраняет порядок назначения обработчиков, а attachEvent в IE - нет.

elem.attachEvent("onclick", handler);
elem.attachEvent("onclick", handler2);
// может быть так, что handler2 сработает раньше handler. 
// так, судя по демке ниже, ведет себя IE.
// а может быть, handler сработает раньше handler2.
// так в демо ниже ведет себя Opera
// ... вообще, порядок неопределен

Демо: порядок срабатывания

На одну и ту же кнопку вешаются пять обработчиков onclick: первый выдает "1", второй выдает "2" и т.п.

Наличие обработчиков

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

В спецификации DOM 3 существует объект eventListenerList, но он слишком новый и на данный момент не поддерживается ни одним из браузеров.

Особенности attachEvent

Обработчик ставится как:

element.attachEvent( "on"+имя_события, обработчик)

Основной недостаток attachEvent заключается в том, что функция-обработчик не получает текущий элемент, на котором сработало событие, ни в каком виде.

Значение this указывает на window, а свойство event.currentTarget отсутствует.

И это достаточно важная особенность!

Например, пусть мы хотим подсвечивать divElem при клике.

Элемент divElem с разным текстом и различными ссылками, и даже с жирным текстом внутри тага <b>

Конечно, же мы повесим обработчик на divElem:

divElem.attachEvent("onclick", handler)

Но при клике из объекта события event в IE можно получить только srcElement, то есть самый глубокий кликнутый элемент. Он может быть ссылкой <a> или элементом <b>, но нам-то нужны не они, а сам divElem, чтобы его подсветить.

Обработчик, добавленный при помощи attachEvent никак не может выяснить объект, на который подвешен.

Впрочем, это легко обойти при помощи небольшого замыкания, корректно передающего указатель this:

divElem.attachEvent("onclick", function() { handler.call(divElem) })

Но этот код порождает утечку памяти в Internet Explorer 6, на который не установлено исправляющее обновление, вышедшее в июне 2007 года, из-за круговой ссылки DOM <-> JS.

  • Можно повесить несколько обработчиков на одно событие
  • Не передается текущий элемент.
  • Поддерживается только IE/Opera.

Особенности addEventListener

Решение W3C работает во всех современных браузерах, кроме Internet Explorer.

Установка обработчика:

element.addEventListener( имя_события, обработчик, фаза)

Пожалуй, особенных недостатков, кроме общих с attachEvent, у этого способа нет.

  • Можно повесить несколько обработчиков на одно событие
  • Умеет вешать обработчики на фазу погружения события
  • Стандарт W3C
  • Не поддерживается IE.

В следующей статье разобран способ, позволяющий добавлять обработчики кроссбраузерно и свободный от описанных недостатков.