Какая разница между 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 event
a <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)); }