Какая разница между addEventListenerа onclick?
var h = document.getElementById("a");
h.onclick = dothing1;
h.addEventListener("click", dothing2);
Приведенный выше код находится вместе в отдельном файле .js, и они оба работают отлично.
Какая разница между addEventListenerа onclick?
var h = document.getElementById("a");
h.onclick = dothing1;
h.addEventListener("click", dothing2);
Приведенный выше код находится вместе в отдельном файле .js, и они оба работают отлично.
Ответы:
Оба являются правильными, но ни один из них не является «лучшим» как таковым, и может быть причина, по которой разработчик решил использовать оба подхода.
Прослушиватели событий (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свойство вторым значением, а также перезаписали оригинальное встроенное onclickсвойство HTML . Проверьте это здесь: http://jsfiddle.net/jpgah/ .
Вообще говоря, не используйте встроенные события . Для этого могут быть конкретные варианты использования, но если вы не уверены на 100%, что у вас есть этот вариант использования, то вы не должны и не должны использовать встроенные события.
Современный Javascript (угловой и тому подобное)
С тех пор как этот ответ был первоначально опубликован, фреймворки 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.
Документация и сопутствующее чтение
function addEvent(e,n,f){return e.attachEvent?e.attachEvent('on'+n,f):e.addEventListener(n,f,!!0)}<< При 98 символах этот более чем на 40% меньше!
Разницу вы можете увидеть, если у вас есть еще пара функций:
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.
В этом ответе я опишу три метода определения обработчиков событий DOM.
element.addEventListener()Пример кода:
element.addEventListener() имеет множество преимуществ:
element.removeEventListener().useCaptureпараметр, который указывает, хотите ли вы обрабатывать событие в фазе захвата или всплытия . См .: Невозможно понять атрибут useCapture в addEventListener ..oneventсвойствам элементов DOM многие неопытные программисты JavaScript считают, что имя события, например, onclickили onload. onэто не часть названия события . Правильные имена событий - это clickи load, и именно так передаются имена событий .addEventListener().element.onevent = function() {}(например onclick, onload)Пример кода:
Это был способ зарегистрировать обработчики событий в DOM 0. Теперь не рекомендуется, потому что:
oneventсвойство обратно в его начальное состояние (т.е. null).window.onload, например:, window.onload = "test";она не выдаст никаких ошибок. Ваш код не будет работать, и было бы очень сложно выяснить, почему. .addEventListener()однако, выдает ошибку (по крайней мере, в Firefox): TypeError: Аргумент 2 из EventTarget.addEventListener не является объектом .oneventатрибут HTML)Пример кода:
Точно так же element.onevent, теперь это не рекомендуется. Помимо проблем, которые element.oneventесть, это:
Content-Security-Policyзаголовок HTTP, чтобы блокировать встроенные сценарии и разрешать внешние сценарии только из доверенных доменов. Посмотрите, как работает Политика безопасности контента?Хотя onclickработает во всех браузерах, addEventListenerне работает в более старых версиях Internet Explorer, который использует attachEventвместо этого.
Недостатком onclickявляется то, что может быть только один обработчик событий, в то время как два других будут запускать все зарегистрированные обратные вызовы.
Насколько я знаю, событие загрузки DOM все еще работает очень ограниченно. Это означает , что он будет стрелять только для window object, imagesи <script>элементы , например. То же самое касается прямого onloadназначения. Между этими двумя нет технической разницы. Вероятно, .onload =имеет лучшую кросс-браузерную доступность.
Тем не менее, вы не можете назначить load eventa <div>или <span>элемент или еще много чего.
addEventListenerМожно добавить несколько событий, тогда как с onclickэтим не может быть сделано.onclickможет быть добавлен как HTMLатрибут, тогда как addEventListenerможет быть добавлен только внутри <script>элементов.addEventListener может принять третий аргумент, который может остановить распространение события.Оба могут быть использованы для обработки событий. Тем не менее, addEventListenerдолжен быть предпочтительным выбором, так как он может делать все onclick , и многое другое. Не используйте inline onclickкак атрибуты HTML, так как это смешивает JavaScript и HTML, что является плохой практикой. Это делает код менее понятным.
onclickобработчики, опасаясь смеха в комнате - но обычно события в последние годы связаны гораздо хуже и менее критично. Такие классы, как js-link, js-form-validationили атрибуты данных с data-jspackage="init"ничем не лучше ... И как часто вы на самом деле используете всплывающие события? Я лично хотел бы иметь возможность написать обработчик, не проверяя, действительно ли цель соответствует моему элементу - или необходимость останавливать распространение в нескольких местах из-за случайных ошибок.
Одна деталь не было замечено еще: современные настольные браузеры рассматривают различные нажатия кнопок , чтобы быть «щелчки» для AddEventListener('click'и onclickпо умолчанию.
onclickи AddEventListenerнажмите огонь на левой и средней кнопкой мыши.onclickсрабатывает только при щелчке левой кнопкой мыши, а при AddEventListenerнажатии левой, средней и правой щелчков.Кроме того, поведение среднего щелчка во всех браузерах очень противоречиво, когда задействованы курсоры прокрутки:
Стоит также отметить, что события «щелчка» для любого HTML-элемента с возможностью выбора с клавиатуры, такие как inputстрельба по пробелу или ввод, когда элемент выбран.
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.
Почему это доминирует сегодня? Это быстрее писать, легче учиться и имеет тенденцию просто работать.
Весь смысл загрузки в 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, поскольку по умолчанию все атрибуты являются строками.
Согласно MDN , разница как показано ниже:
addEventListener:
Метод EventTarget.addEventListener () добавляет указанный EventListener-совместимый объект в список прослушивателей событий для указанного типа события в EventTarget, для которого он вызывается. Целью события может быть элемент в документе, сам документ, окно или любой другой объект, который поддерживает события (например, XMLHttpRequest).
по щелчку:
Свойство 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);
по щелчку:
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!");
}
Если вы не слишком беспокоитесь о поддержке браузера, есть способ перепривязать ссылку «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, и, вероятно, есть некоторая шумиха вокруг совместимости «bind» с другими браузерами.
Использование встроенных обработчиков несовместимо с политикой безопасности контента, поэтому этот addEventListenerподход более безопасен с этой точки зрения. Конечно, вы можете включить встроенные обработчики с помощью, unsafe-inlineно, как следует из названия, это небезопасно, поскольку возвращает целые толпы эксплойтов JavaScript, которые предотвращает CSP.
Также должно быть возможно либо расширить слушатель, прототипируя его (если у нас есть ссылка на него, а не анонимная функция), либо сделать вызов onclick для вызова библиотеки функций (функция, вызывающая другие функции).
подобно
elm.onclick = myFunctionList
function myFunctionList(){
myFunc1();
myFunc2();
}
это означает, что нам никогда не придется изменять вызов onclick, просто измените функцию myFunctionList (), чтобы делать то, что мы когда-либо захотим, но это оставляет нас без контроля фаз пузыря / перехвата, поэтому следует избегать для новых браузеров.
на всякий случай кто-нибудь найдет эту ветку в будущем ...
element.onclick = function () {/ * делать вещи * /}
element.addEventListener ('click', function () {/ * do stuff * /}, false);
Очевидно, они делают то же самое: прослушивают событие click и выполняют функцию обратного вызова. Тем не менее, они не эквивалентны. Если вам когда-нибудь понадобится выбрать один из двух вариантов, это поможет вам определить, какой из них лучше для вас.
Основное отличие состоит в том, что onclick - это просто свойство , и, как и все свойства объекта, если вы напишите более одного раза, оно будет перезаписано . Вместо этого с помощью addEventListener () мы можем просто привязать обработчик события к элементу и вызывать его каждый раз, когда нам это нужно, не беспокоясь о каких-либо перезаписанных свойствах. Пример показан здесь,
Попробуйте это: https://jsfiddle.net/fjets5z4/5/
Во-первых, я испытывал желание продолжать использовать onclick, потому что он короче и выглядит проще… и на самом деле так оно и есть. Но я не рекомендую использовать его больше. Это похоже на использование встроенного JavaScript. Использование чего-то подобного - встроенного JavaScript - в настоящее время крайне нежелательно (встроенный CSS тоже не рекомендуется, но это уже другая тема).
Однако функция addEventListener (), несмотря на то, что она стандартна, просто не работает в старых браузерах (Internet Explorer ниже версии 9), и это еще одно большое отличие. Если вам нужно поддерживать эти древние браузеры, вы должны следовать по принципу onclick. Но вы также можете использовать jQuery (или одну из его альтернатив): он в основном упрощает вашу работу и уменьшает различия между браузерами, поэтому может сэкономить вам много времени.
var clickEvent = document.getElementByID("onclick-eg");
var EventListener = document.getElementByID("addEventListener-eg");
clickEvent.onclick = function(){
window.alert("1 is not called")
}
clickEvent.onclick = function(){
window.alert("2 is not called")
}
EventListener.addEventListener("click",function(){
window.alert("1 is called")
})
EventListener.addEventListener("click",function(){
window.alert("2 is also called")
})
addEventListener позволяет установить несколько обработчиков, но не поддерживается в IE8 или ниже.
IE есть attachEvent, но это не совсем то же самое.
Контекст, на который ссылается '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, что является непоследовательностью. Кстати, если вы используете jQuery ( $('#btnSubmit').on('click', disable);), он использует явное связывание.
btnSubmit.onclick = disable;(назначить функцию, а не вызывать ее). Тогда в обоих случаях thisбудет ссылаться на элемент кнопки.
onclick - это, по сути, addEventListener, который специально выполняет функцию при нажатии на элемент. Так что полезно, когда у вас есть кнопка, которая выполняет простые операции, например кнопка калькулятора. addEventlistener может использоваться для множества вещей, таких как выполнение операции, когда загружен DOM или весь контент, похожий на window.onload, но с большим контролем.
Обратите внимание, что вы можете использовать несколько событий со встроенными функциями или, по крайней мере, с помощью onclick, разделив каждую функцию точкой с запятой, как показано ниже ....
Я бы не стал писать функции со встроенными функциями, поскольку у вас могли бы возникнуть проблемы позже, и это было бы беспорядочно. Просто используйте его для вызова функций, уже выполненных в вашем файле скрипта.
Какой вы используете, я полагаю, будет зависеть от того, что вы хотите. addEventListener для сложных операций и onclick для простых. Я видел, что некоторые проекты не привязывают определенный элемент к элементам и вместо этого реализуют более глобальный список событий, который будет определять, было ли нажатие на кнопку, и выполнять определенные задачи в зависимости от того, что было нажато. Imo, которые потенциально могут привести к проблемам, я бы подумал, и хотя и небольшая, возможно, пустая трата ресурсов, если бы этот обработчик событий должен был обрабатывать каждый щелчок
function addEvent(element, myEvent, fnc) { return ((element.attachEvent) ? element.attachEvent('on' + myEvent, fnc) : element.addEventListener(myEvent, fnc, false)); }