Вот несколько примеров, которые могут помочь людям лучше понять свои проблемы и устранить их.
TL; DR
on*обработчики событий (например, onclickатрибут в элементе кнопки): вернуть false для отмены события
addEventListenerэто другой API, возвращаемые значения (например false) игнорируются: use event.preventDefault().
onclick="<somejs>"имеет свою собственную потенциальную путаницу, потому что <somejs>заключен в тело функции onclick.
- Используйте
getEventListenersAPI инструментов разработчика браузера, чтобы увидеть, как выглядит ваш прослушиватель событий, чтобы устранить неполадки, если ваш обработчик событий ведет себя не так, как ожидалось.
пример
Этот пример специфичен для clickсобытия со <a>ссылкой ... но может быть обобщен для большинства типов событий.
У нас есть якорь (ссылка) с классом, js-some-link-hookкоторый мы хотим открыть в модальном окне и предотвратить любую навигацию по странице.
Приведенные ниже примеры были запущены в google chrome (71) на MacOS Mojave.
Одна из основных ошибок заключается в предположении, что onclick=functionNameэто то же поведение, что и при использованииaddEventListener
Допустим, у нас есть тег привязки (ссылка), который мы хотим обрабатывать с помощью javascript, когда javascript включен. Мы не хотим, чтобы браузер переходил по ссылке при нажатии (поведение «предотвратить по умолчанию»).
<a href="https://www.example.com/url/to/go/to/when/no/javascript"
class="js-some-link-hook">click me!</a>
атрибут onclick
function eventHandler (event) {
alert('eventHandler ran');
return false;
}
function addEventListenerToElement () {
var link = document.querySelector('.js-some-link-hook');
link.setAttribute('onclick', eventHandler);
}
addEventListenerToElement();
Затем запустите в консоли разработчика браузера:
var el = document.querySelector('a.js-some-link-hook'),
listener = getEventListeners(el).click[0].listener;
console.log(''+listener);
... и вы видите:
function onclick(event) {
function eventHandler (event) {alert('eventHandler ran'); return false;}
}
Это вообще не работает. При использовании onclick=вашего обработчика функция обернута в другую функцию.
Вы можете видеть, что мое определение функции включено, но не вызывается, потому что я указал ссылку на функцию, не вызывая ее. т.е. нам onclick="functionName()"не onclick="functionName"нужно убедиться, что functionNameон запускается при нажатии на элемент.
Кроме того, вы можете видеть, что даже если моя функция была вызвана и моя функция вернула false ... onclickфункция не вернет это ложное значение ... которое требуется для «отмены» события.
Чтобы исправить это, мы можем установить onclickзначение, return myHandlerFunc();которое гарантирует, что onclickвозвращается возвращаемое значение (false) из myHandlerFunc.
Вы также можете удалить return false;из myHandlerFuncи изменить как onclickбыть, myHandlerFunc(); return false;но это не имеет смысла, поскольку вы, вероятно, захотите сохранить логику в своей функции обработчика.
Обратите внимание, что при настройке onclickс помощью javascript , когда вы настраиваете onclickнепосредственно в html, а не с помощью javascript (как в моих примерах), onclickзначение атрибута представляет собой строку типа, и все работает. Если вы настраиваете onclickс помощью javascript, вам нужно обратить внимание на тип. Если вы скажете, element.setAttribute('onclick', myHandlerFunc()) myHandlerFuncбудет запущен прямо сейчас, а результат будет сохранен в атрибуте ... а не запускаться при каждом щелчке. Вместо этого вы должны убедиться, что значение атрибута задано как строка. element.setAttribute('onclick', 'return myHandlerFunc();')
Теперь, когда мы видим, как это работает, мы можем изменить код, чтобы делать все, что захотим. Странный пример для иллюстрации (не используйте этот код):
function eventHandler (e) {
alert('eventHandler ran');
console.log(e);
return false;
}
function addEventListenerToElement () {
var link = document.querySelector('.js-some-link-hook');
link.setAttribute('onclick', 'return ('+eventHandler+')(event);');
}
addEventListenerToElement();
Вы видите, что мы заключили определение нашей функции eventHandler в строку. В частности: самоисполняющаяся функция с оператором возврата впереди.
Снова в консоли chrome devtools:
var el = document.querySelector('a.js-some-link-hook'),
listener = getEventListeners(el).click[0].listener;
console.log(''+listener);
... показывает:
function onclick(event) {
return (function eventHandler (e) {
alert('eventHandler ran');
console.log(e);
return false;
})(event);
}
... так что да, это должно сработать. Разумеется, если мы нажмем на ссылку, мы получим предупреждение и, отклонив предупреждение, страница не будет перемещаться и не обновится.
Еще одно примечание о onclick... Если вы хотите получить и использовать eventпараметр во время события, вы должны отметить, что он называется «событие». Вы можете получить к нему доступ в своем обработчике, используя имя event(доступно через область родительской onclickфункции). Или вы можете eventсоздать свой обработчик, который будет принимать его в качестве параметра (лучше для тестирования) ... например, onclick="return myEventHandler(event);"или как вы видите в предыдущем примере.
addEventListener
function eventHandler (ev) {
alert('eventHandler ran');
console.log(ev);
return false;
}
function addEventListenerToElement () {
var link = document.querySelector('.js-some-link-hook');
link.addEventListener('click', eventHandler, false);
}
addEventListenerToElement();
инструменты разработчика браузера:
var el = document.querySelector('a.js-some-link-hook'),
listener = getEventListeners(el).click[0].listener;
console.log(''+listener);
результат:
function eventHandler (ev) {
alert('eventHandler ran');
console.log(ev);
return false;
}
Так что разница уже видна. С addEventListenerмы не обернуты в onclickфункции. Наш обработчик получает eventпараметр напрямую (и поэтому мы можем называть его как угодно). Также наш здесь return falseнаходится на «верхнем уровне», и нам не нужно беспокоиться о добавлении дополнительных операторов возврата, таких как with onclick.
Похоже, это должно работать. При переходе по ссылке получаем оповещение. Закройте предупреждение, и страница будет перемещаться / обновляться. т.е. событие НЕ было отменено возвратом false.
Если мы посмотрим на спецификацию (см. Ресурсы внизу), мы увидим, что наша функция обратного вызова / обработчика для addEventListener не поддерживает возвращаемый тип. Мы можем вернуть все, что захотим, но поскольку это не является частью API / интерфейса браузера, это не имеет никакого эффекта.
Решение: использовать event.preventDefault()вместо return false;...
function eventHandler (ev) {
ev.preventDefault();
alert('eventHandler ran');
}
function addEventListenerToElement () {
var link = document.querySelector('.js-some-link-hook');
link.addEventListener('click', eventHandler, false);
}
addEventListenerToElement();
инструменты разработчика браузера ...
var el = document.querySelector('a.js-some-link-hook'),
listener = getEventListeners(el).click[0].listener;
console.log(''+listener);
дает ...
function eventHandler (ev) {
ev.preventDefault();
alert('eventHandler ran');
}
...как и ожидалось.
Снова тестирование:
- Щелкните ссылку.
- Получите оповещение.
- Отключить оповещение.
- Никакой навигации по страницам или обновления не происходит ... это то, что мы хотим.
Таким образом, при addEventListenerиспользовании event.preventDefault()as возврат false ничего не делает.
Ресурсы
Спецификация html5 ( https://www.w3.org/TR/html5/webappapis.html#events ) сбивает с толку, потому что они используют оба onclickи addEventListenerв своих примерах, и говорят следующее:
Алгоритм обработки обработчика событий для обработчика событий H и объекта события E следующий:
...
- Обработайте возвращаемое значение следующим образом:
...
Если возвращаемое значение - логическое ложное значение Web IDL, отмените событие.
Таким образом, похоже, это означает, что return falseсобытие отменяется для обоих addEventListenerи onclick.
Но если вы посмотрите на их связанное определение, event-handlerвы увидите:
У обработчика событий есть имя, которое всегда начинается с «on» и сопровождается именем события, для которого он предназначен.
...
Обработчики событий доступны одним из двух способов.
Первый способ, общий для всех обработчиков событий, - это использование IDL-атрибута обработчика событий.
Второй способ - это атрибут содержимого обработчика событий. Таким образом отображаются обработчики событий в элементах HTML и некоторые обработчики событий в объектах Window.
https://www.w3.org/TR/html5/webappapis.html#event-handler
Таким образом, кажется, что return falseотмена события действительно применяется только к onclick(или вообще on*) обработчикам событий, а не к обработчикам событий, зарегистрированным через addEventListenerкоторые имеет другой API.
Поскольку addEventListenerAPI не входит в спецификацию html5 (только on*обработчики событий) ... было бы менее запутанно, если бы они on*в своих примерах придерживались обработчиков событий стиля.