addEventListener против onclick

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

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

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

14 ответов


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

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

более ранние версии 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= "" свойство и элемент.функция 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'); };

... когда вы нажали элемент, вы бы только см. "Did stuff #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/

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

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


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

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


в этом ответе я опишу три метода определения обработчиков событий 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 в addEventListener.
  • заботится о семантика. В принципе, это делает регистрацию обработчиков событий более явной. Для новичка вызов функции делает очевидным, что что происходит, тогда как назначение события некоторому свойству элемента DOM, по крайней мере, не интуитивно.
  • позволяет структура отдельного документа (HTML) и логика (JavaScript). В крошечных веб-приложениях это может показаться не важным, но это тут дело с любым большим проектом. Гораздо проще поддерживать проект, который разделяет структуру и логику, чем проект, который этого не делает.
  • устраняет путаницу с правильными именами событий. Из-за использования встроенных прослушивателей событий или назначения прослушивателей событий .onevent свойства элементов DOM, много неопытных программистов JavaScript думает, что например, имя события onclick или onload. on и не часть имени события. Правильные имена событий click и load, и именно так имена событий передаются в .addEventListener().
  • работает в почти всех браузеров. Если вам все еще нужно поддерживать IE полифилл из 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 намного более вредным. В настоящее время веб-сайты должны отправлять правильные Content-Security-Policy HTTP-заголовок для блокировки встроенных скриптов и разрешения только внешних скриптов из доверенных доменов. См.как работает политика безопасности контента?
  • не отдельная структура документа и логике.
  • если вы создаете свою страницу с помощью сценария на стороне сервера, и, например, вы создаете сто ссылок, каждая с тем же встроенным обработчиком событий, ваш код будет намного длиннее, чем если бы обработчик событий был определен только один раз. Это означает, что клиент придется загружать больше контента, и в результате ваш сайт будет медленнее.

см. также


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

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


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

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


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


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


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

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

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

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

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


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

как

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

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

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


по данным MDN, разница, как показано ниже:

addEventListener:

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

onclick:

свойство onclick возвращает код обработчика событий click на элемент тока. При использовании события click для запуска действия также попробуйте добавить этот же действие на событие keydown, чтобы использование того же действия людьми, которые не используют мышь или прикосновение экран. Элемент синтаксиса.onclick = functionRef; где functionRef является function-часто имя объявленной функции в другом месте или функции выражение. См. "руководство для 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!");
}

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

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


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))))

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

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

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

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


резюме:

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

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


контекст, на который ссылается '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 будет инициировано нажатием кнопки, однако кнопка не будет отключена, поскольку между кнопкой нет явной привязки.функция onclick и обработчик события onclick. При отладке вижу 'this' объект, вы можете видеть, что он относится к