AddEventListener vs onclick

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

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

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

Ответы

Ответ 1

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

Слушатели событий (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.

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

Ответ 2

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

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.

Ответ 3

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

element.addEventListener()

Пример кода:

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

Ответ 4

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

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

Ответ 5

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

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

Ответ 6

Если вы не слишком беспокоитесь о поддержке браузера, есть способ восстановить ссылку '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, и, возможно, есть некоторый подгон, который делает привязку совместимой с другими браузерами.

Ответ 7

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

Ответ 8

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

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

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

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

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

Ответ 9

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

как

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

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

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

Ответ 10

Согласно 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!");
}

Ответ 11

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

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

Ответ 12

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, поскольку по умолчанию атрибуты - это все строки.

Ответ 13

Резюме:

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

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

Ответ 14

Контекст, на который ссылается ключевое слово '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);), он использует явное связывание.