AddEventListener vs onclick

Какая разница между addEventListener и onclick?

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

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

+539
источник поделиться
14 ответов

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

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

Более ранние версии Internet Explorer реализуют javascript по-разному от почти любого другого браузера. С версиями менее 9 вы используете метод attachEvent [ doc], например:

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

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

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

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

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

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

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

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

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

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

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

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

... является эквивалентом встроенного javascript, за исключением того, что вы больше контролируете область (поскольку вы пишете script, а не 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/.

Что лучше?

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

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/

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

Документация и связанное с ней чтение

+770
источник

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

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 (который имеет несколько иной синтаксис) в IE <9.

+138
источник

В этом ответе я опишу три метода определения обработчиков событий 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 polyfill из 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 не является объектом.
  • Не позволяет выбрать, хотите ли вы обрабатывать событие на этапе захвата или пузырька.

Обработчики событий Inline (onevent атрибут HTML)

Пример кода:

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

Аналогично element.onevent, теперь он обескуражен. Помимо проблем, которые имеет element.onevent, он:

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

См. также

+46
источник

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

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

+17
источник

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

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

+12
источник

Если вы не слишком беспокоитесь о поддержке браузера, есть способ восстановить ссылку 'this' в функции, вызванной событием. Он обычно указывает на элемент, который генерировал событие, когда функция выполняется, что не всегда то, что вы хотите. Сложная часть состоит в том, чтобы одновременно удалить одного и того же прослушивателя событий, как показано в этом примере: http://jsfiddle.net/roenbaeck/vBYu3/

/*
    Testing that the function returned from bind is rereferenceable, 
    such that it can be added and removed as an event listener.
*/
function MyImportantCalloutToYou(message, otherMessage) {
    // the following is necessary as calling bind again does 
    // not return the same function, so instead we replace the 
    // original function with the one bound to this instance
    this.swap = this.swap.bind(this); 
    this.element = document.createElement('div');
    this.element.addEventListener('click', this.swap, false);
    document.body.appendChild(this.element);
}
MyImportantCalloutToYou.prototype = {
    element: null,
    swap: function() {
        // now this function can be properly removed 
        this.element.removeEventListener('click', this.swap, false);           
    }
}

Приведенный выше код хорошо работает в Chrome, и, возможно, есть некоторый подгон, который делает привязку совместимой с другими браузерами.

+1
источник

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

+1
источник

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

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

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

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

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

+1
источник

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

как

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

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

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

+1
источник

Согласно MDN, разница следующая:

addEventListener:

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

по щелчку:

Свойство onclick возвращает код обработчика события клика для текущего элемента. При использовании события 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);

по щелчку:

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
источник

addEventListener позволяет устанавливать несколько обработчиков, но не поддерживается в IE8 или ниже.

IE имеет attachEvent, но это не совсем то же самое.

0
источник

Javascript имеет тенденцию смешивать все с объектами, и это может сбить с толку. Все в одном - это способ JavaScript.

По существу onclick - это атрибут HTML. И наоборот, addEventListener - это метод объекта DOM, представляющий элемент HTML.

В объектах JavaScript метод - это просто свойство, которое имеет функцию как значение и работает против объекта, к которому он привязан (используя это, например).

В JavaScript, поскольку HTML-элемент, представленный DOM, будет иметь атрибуты, сопоставленные его свойствам.

Здесь люди путаются, потому что JavaScript объединяет все в один контейнер или пространство имен без слоя косвенности.

В обычном макете OO (который, по крайней мере, объединяет пространство имен свойств/методов), вы могли бы иметь что-то вроде:

domElement.addEventListener // Object(Method)
domElement.attributes.onload // Object(Property(Object(Property(String))))

Есть такие варианты, как он может использовать getter/setter для onload или HashMap для атрибутов, но в конечном счете, как он будет выглядеть. JavaScript устранил этот слой косвенности, ожидая узнать, что среди прочего. Он объединил domElement и атрибуты вместе.

Устранение совместимости, которую вы должны использовать в качестве лучшей практики, использует addEventListener. Поскольку другие ответы говорят о различиях в этом отношении, а не о фундаментальных программных различиях, я откажусь от этого. По сути, в идеальном мире вы действительно должны использовать только * из HTML, но в еще более идеальном мире вы не должны делать что-либо подобное из HTML.

Почему это доминирует сегодня? Это быстрее писать, легче учиться и имеет тенденцию просто работать.

Весь смысл загрузки в HTML - это, в первую очередь, доступ к методу или функциям addEventListener. Используя его в JS, вы просматриваете HTML, когда можете применить его напрямую.

Гипотетически вы можете создавать свои собственные атрибуты:

$('[myclick]').each(function(i, v) {
     v.addEventListener('click', function() {
         eval(v.myclick); // eval($(v).attr('myclick'));
     });
});

То, что делает JS, немного отличается от этого.

Вы можете приравнять его к чему-то вроде (для каждого созданного элемента):

element.addEventListener('click', function() {
    switch(typeof element.onclick) {
          case 'string':eval(element.onclick);break;
          case 'function':element.onclick();break;
     }
});

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

Возможно, это взлом совместимости, который вы можете привязать к атрибуту on, поскольку по умолчанию атрибуты - это все строки.

0
источник

Резюме:

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

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

0
источник

Контекст, на который ссылается ключевое слово 'this' в JavasSript, отличается.

посмотрите следующий код:

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title></title>

</head>
<body>
    <input id="btnSubmit" type="button" value="Submit" />
    <script>
        function disable() {
            this.disabled = true;
        }
        var btnSubmit = document.getElementById('btnSubmit');
        btnSubmit.onclick = disable();
        //btnSubmit.addEventListener('click', disable, false);
    </script>
</body>
</html>

То, что он делает, действительно просто. при нажатии кнопки кнопка автоматически отключается.

Сначала, когда вы пытаетесь подключить события таким образом button.onclick = function(), Событие onclick будет вызвано нажатием кнопки, однако кнопка не будет отключена, потому что нет явного связывания между button.onclick и обработчиком события onclick. Если вы отлаживаете объект 'this', вы можете увидеть, что он относится к объекту 'window'.

Во-вторых, если вы прокомментируете btnSubmit.onclick = disable(); и раскомментируете //btnSubmit.addEventListener('click', disable, false); вы можете видеть, что кнопка отключена, потому что таким образом существует явная привязка между событием button.onclick и обработчиком события onclick. Если вы отлаживаете функцию отключения, вы можете видеть, что 'this' относится к button control, а не к window.

Это то, что мне не нравится в JavaScript, что является несогласованностью. Btw, если вы используете jQuery ($('#btnSubmit').on('click', disable);), он использует явное связывание.

-1
источник

Посмотрите другие вопросы по меткам или Задайте вопрос