addEventListener против onclick - PullRequest
622 голосов
/ 14 июня 2011

В чем разница между addEventListener и onclick?

var h = document.getElementById("a");
h.onclick = dothing1;
h.addEventListener("click", dothing2);

Приведенный выше код находится вместе в отдельном файле .js, и они оба прекрасно работают.

Ответы [ 14 ]

858 голосов
/ 14 июня 2011

Оба являются правильными, но ни один из них не является «лучшим» как таковым, и может быть причина, по которой разработчик решил использовать оба подхода.

Прослушиватели событий (addEventListener и IE attachEvent)

В более ранних версиях Internet Explorer JavaScript реализован не так, как в большинстве других браузеров.В версиях менее 9 вы используете метод attachEvent [ doc ], например:

element.attachEvent('onclick', function() { /* do stuff here*/ });

В большинстве других браузеров (включая IE 9 и выше) вы используете addEventListener [ doc ], например:

element.addEventListener('click', function() { /* do stuff here*/ }, false);

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

Приведенные выше примеры представляют использование анонимной функции [ doc ].Вы также можете добавить прослушиватель событий, используя ссылку на функцию [ doc ] или замыкание [ doc ]:

var myFunctionReference = function() { /* do stuff here*/ }

element.attachEvent('onclick', myFunctionReference);
element.addEventListener('click', myFunctionReference , false);

Другая важная функция addEventListener - этопоследний параметр, который управляет реакцией слушателя на всплывающие события [ doc ].Я передавал false в примерах, что является стандартным для, вероятно, 95% случаев использования.Не существует эквивалентного аргумента для attachEvent или при использовании встроенных событий.

Встроенные события (свойство HTML onclick = "" и element.onclick)

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

<a id="testing" href="#" onclick="alert('did stuff inline');">Click me</a>

Большинство опытных разработчиков избегают этого метода, но он выполняет свою работу;это просто и прямо.Вы не можете использовать здесь замыкания или анонимные функции (хотя сам обработчик является своего рода анонимной функцией), и ваш контроль над областью ограничен.

Другой упомянутый вами метод:

element.onclick = function () { /*do stuff here */ };

... является эквивалентом встроенного JavaScript, за исключением того, что вы имеете больший контроль над областью (поскольку вы пишете сценарий, а не HTML) и можете использовать анонимные функции, ссылки на функции и / или замыкания.

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

Используя пример <a> из приведенного выше HTML-кода:

var element = document.getElementById('testing');
element.onclick = function () { alert('did stuff #1'); };
element.onclick = function () { alert('did stuff #2'); };

... когда вы щелкаете элемент, вы только видите «Сделал материал №2» - вы перезаписали первое назначенное свойство onclick вторым значением, и выперезаписал оригинальное встроенное свойство HTML onclick.Проверьте это здесь: http://jsfiddle.net/jpgah/.

Вообще говоря, не использовать встроенные события .Для этого могут быть конкретные варианты использования, но если вы не уверены на 100%, что у вас есть этот вариант использования, то вы не должны и не должны использовать встроенные события.

Modern Javascript (Angular и т. П.)

С тех пор как этот ответ был первоначально опубликован, фреймворки javascript, такие как Angular, стали гораздо более популярными.Такой код вы увидите в шаблоне Angular:

<button (click)="doSomething()">Do Something</button>

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

Что лучше?

Вопрос в совместимости и необходимости браузера.Вам в настоящее время нужно прикрепить более одного события к элементу?Будете ли вы в будущем?Скорее всего, вы будете.attachEvent и addEventListener необходимы.Если нет, встроенное событие может показаться, что они справятся с задачей, но вам гораздо лучше подготовиться к будущему, которое, хотя и может показаться маловероятным, по крайней мере, предсказуемо.Есть шанс, что вам придется перейти к слушателям событий на основе JS, так что вы можете просто начать там.Не используйте встроенные события.

jQuery и другие платформы javascript инкапсулируют различные реализации браузером событий DOM уровня 2 в общих моделях, поэтому вы можете писать кросс-браузерный совместимый код, не беспокоясь об истории IE как мятежника,Тот же код с jQuery, все кросс-браузерные и готовые к работе:

$(element).on('click', function () { /* do stuff */ });

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

function addEvent(element, evnt, funct){
  if (element.attachEvent)
   return element.attachEvent('on'+evnt, funct);
  else
   return element.addEventListener(evnt, funct, false);
}

// example
addEvent(
    document.getElementById('myElement'),
    'click',
    function () { alert('hi!'); }
);

Попробуйте: http://jsfiddle.net/bmArj/

Принимая все это во внимание, если только вы не используете скриптПри взгляде на различия в браузере учитывались иным образом (в коде, не показанном в вашем вопросе), часть, использующая addEventListener, не будет работать в версиях IE менее 9.

Документация и сопутствующее чтение

156 голосов
/ 14 июня 2011

Разница, которую вы могли бы увидеть, если бы у вас была другая пара функций:

var h = document.getElementById('a');
h.onclick = doThing_1;
h.onclick = doThing_2;

h.addEventListener('click', doThing_3);
h.addEventListener('click', doThing_4);

Функции 2, 3 и 4 работают, а 1 - нет. Это связано с тем, что addEventListener не перезаписывает существующие обработчики событий, тогда как onclick переопределяет любые существующие onclick = fn обработчики событий.

Другое существенное отличие, конечно, в том, что onclick всегда будет работать, тогда как addEventListener не работает в Internet Explorer до версии 9. Вы можете использовать аналогичный attachEvent (который имеет слегка *) 1013 * другой синтаксис) в IE <9. </p>

55 голосов
/ 30 января 2016

В этом ответе я опишу три метода определения обработчиков событий DOM.

element.addEventListener()

Пример кода:

const element = document.querySelector('a');
element.addEventListener('click', event => event.preventDefault(), true);
<a href="//google.com">Try clicking this link.</a>

element.addEventListener() имеет несколько преимуществ:

  • Позволяет зарегистрировать неограниченное число обработчиков и удалить их.с element.removeEventListener().
  • Имеет параметр useCapture, который указывает, хотите ли вы обрабатывать событие в его фазе захвата или всплытия .См .: Невозможно понять атрибут useCapture в addEventListener .
  • Заботится о семантике .По сути, это делает регистрацию обработчиков событий более явной.Для новичка вызов функции делает очевидным, что что-то происходит , тогда как присвоение события какому-либо свойству элемента DOM, по крайней мере, не интуитивно понятно.
  • Позволяет отдельную структуру документа(HTML) и логика (JavaScript) .В крошечных веб-приложениях это может показаться неважным, но имеет значение для любого более крупного проекта.Намного проще поддерживать проект, который разделяет структуру и логику, чем проект, который не делает.
  • Устраняет путаницу с правильными именами событий.Из-за использования встроенных прослушивателей событий или назначения прослушивателей событий для свойств .onevent элементов DOM многие неопытные программисты JavaScript считают, что имя события, например, onclick или onload.on - это , а не часть имени события .Правильные имена событий: click и load, и именно так имена событий передаются в .addEventListener().
  • . Работает в почти во всех браузерах .Если вам все еще требуется поддержка IE <= 8, вы можете использовать <a href="https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener#Compatibility" rel="noreferrer"> полизаполнение из MDN .

element.onevent = function() {} (например, onclick, onload)

Пример кода:

const element = document.querySelector('a');
element.onclick = event => event.preventDefault();
<a href="//google.com">Try clicking this link.</a>

Это был способ регистрации обработчиков событий в DOM 0. Теперь не рекомендуется, потому что:

  • Позволяет вам зарегистрироваться только один обработчик событий.Кроме того, удаление назначенного обработчика не является интуитивно понятным, поскольку для удаления обработчика событий, назначенного с помощью этого метода, необходимо вернуть свойство onevent обратно в исходное состояние (т. Е. null).
  • Не реагировать на ошибки соответственно.Например, если вы по ошибке назначите строку для window.onload, например: window.onload = "test";, она не выдаст никаких ошибок.Ваш код не будет работать, и было бы очень сложно выяснить, почему..addEventListener() однако выдает ошибку (по крайней мере, в Firefox): TypeError: Аргумент 2 для EventTarget.addEventListener не является объектом .
  • Не предоставляет способ выбора, если выхотите обработать событие в его фазе захвата или всплытия.

Встроенные обработчики событий (onevent атрибут HTML)

Пример кода:

<a href="//google.com" onclick="event.preventDefault();">Try clicking this link.</a>

Так же, как и element.onevent, теперь это не рекомендуется.Помимо проблем, которые есть у element.onevent, он:

  • является потенциальной проблемой безопасности , поскольку делает XSS намного более вредным.В настоящее время веб-сайты должны отправлять правильный заголовок HTTP Content-Security-Policy, чтобы блокировать встроенные сценарии и разрешать внешние сценарии только из доверенных доменов.См. Как работает Политика безопасности контента?
  • Не не разделяет структуру и логику документа .
  • Если вы генерируете свою страницу с помощью серверного скрипта и, например, генерируете сотню ссылок, каждая с одним и тем же встроенным обработчиком событий, ваш код будет намного длиннее, чем если бы обработчик событий был определен только один раз.Это означает, что клиенту придется загружать больше контента, и в результате ваш сайт будет работать медленнее.

См. Также

20 голосов
/ 14 июня 2011

Хотя onclick работает во всех браузерах, addEventListener не работает в более старых версиях Internet Explorer, где вместо него используется attachEvent.

Недостатком onclick является то, что может быть только один обработчик событий, в то время как два других вызовут все зарегистрированные обратные вызовы.

12 голосов
/ 01 августа 2011

Насколько я знаю, событие загрузки DOM все еще работает очень ограниченно.Это означает, что он будет срабатывать только для элементов window object, images и <script>.То же самое относится и к прямому назначению onload.Между этими двумя нет технической разницы.Вероятно, .onload = имеет лучшую кросс-браузерную доступность.

Однако вы не можете назначить load event элементу <div> или <span> или еще много чего.

4 голосов
/ 25 августа 2018

Сводка:

  1. addEventListener может добавить несколько событий, тогда как с onclick это невозможно сделать.
  2. onclick можно добавить как атрибут HTMLтогда как addEventListener может быть добавлен только в <script> элементах.
  3. addEventListener может принимать третий аргумент, который может остановить распространение события.

Можно использовать обаобрабатывать события.Однако addEventListener должен быть предпочтительным выбором, поскольку он может делать все, что делает onclick и даже больше.Не используйте inline onclick в качестве атрибутов HTML, так как это смешивает JavaScript и HTML, что является плохой практикой.Это делает код менее понятным.

2 голосов
/ 27 апреля 2017

Согласно MDN , разница как показано ниже:

addEventListener:

Метод EventTarget.addEventListener () добавляет указанный EventListener-совместимый объект в списке слушателей событий для указанный тип события в EventTarget, для которого он вызывается. целью события может быть элемент в документе, сам документ, Окно или любой другой объект, который поддерживает события (например, XMLHttpRequest).

OnClick:

Свойство onclick возвращает код обработчика события click для текущий элемент. При использовании события click для запуска действия также рассмотрите возможность добавления этого же действия в событие keydown, чтобы использование этого же действия людьми, которые не используют мышь или прикосновение экран. Синтаксис element.onclick = functionRef; где functionRef является функция - часто имя функции, объявленной в другом месте или функции выражение. Подробнее см. "Руководство по JavaScript: функции".

Существует также синтаксическая разница в использовании, как показано в следующих кодах:

addEventListener:

// Function to change the content of t2
function modifyText() {
  var t2 = document.getElementById("t2");
  if (t2.firstChild.nodeValue == "three") {
    t2.firstChild.nodeValue = "two";
  } else {
    t2.firstChild.nodeValue = "three";
  }
}

// add event listener to table
var el = document.getElementById("outside");
el.addEventListener("click", modifyText, false);

OnClick:

function initElement() {
    var p = document.getElementById("foo");
    // NOTE: showAlert(); or showAlert(param); will NOT work here.
    // Must be a reference to a function name, not a function call.
    p.onclick = showAlert;
};

function showAlert(event) {
    alert("onclick Event detected!");
}
1 голос
/ 25 июля 2015

Должна также быть возможность либо расширить слушатель, создав его прототип (если у нас есть ссылка на него, а не анонимная функция), либо сделать вызов onclick для вызова библиотеки функций (функция, вызывающая другоефункции)

как

    elm.onclick = myFunctionList
    function myFunctionList(){
      myFunc1();
      myFunc2();
    }

это означает, что нам никогда не придется изменять вызов onclick, просто измените функцию myFunctionList (), чтобы делать то, что мы хотим, но это оставляет нас без контроля над пузырьками/ ловить фазы, поэтому следует избегать для новых браузеров.

на всякий случай, если кто-то найдет эту ветку в будущем ...

1 голос
/ 30 июня 2015

Одна деталь еще не была замечена: современные браузеры настольных компьютеров считают, что различные нажатия кнопок являются «щелчками» для AddEventListener('click' и onclick по умолчанию.

  • В Chrome 42 и IE11,onclick и AddEventListener щелкают по левому и среднему щелчку.
  • В Firefox 38 onclick запускает только при левом щелчке, но AddEventListener щелчок срабатывает слева,средние и щелчки правой кнопкой мыши.

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

  • В Firefox события среднего щелчка всегда запускаются.
  • В Chrome они не запускаются, если средний щелчок открывает или закрывает курсор прокрутки.
  • В IE они запускаются, когда курсор прокруткизакрывается, но не при открытии.

Стоит также отметить, что события "щелчка" для любого HTML-элемента с возможностью выбора с клавиатуры, такого как input, также запускаются на пробел или вводятся при выборе элемента.

1 голос
/ 20 апреля 2015

Использование встроенных обработчиков несовместимо с Политика безопасности контента , поэтому подход addEventListener более безопасен с этой точки зрения.Конечно, вы можете включить встроенные обработчики с помощью unsafe-inline, но, как следует из названия, это небезопасно, так как возвращает целые толпы эксплойтов JavaScript, которые предотвращает CSP.

...