Вот несколько примеров, которые могут помочь людям лучше понять свои проблемы и устранить их.
TL; DR
on*
обработчики событий (например, onclick
атрибут в элементе кнопки): вернуть false для отмены события
addEventListener
это другой API, возвращаемые значения (например false
) игнорируются: use event.preventDefault()
.
onclick="<somejs>"
имеет свою собственную потенциальную путаницу, потому что <somejs>
заключен в тело функции onclick.
- Используйте
getEventListeners
API инструментов разработчика браузера, чтобы увидеть, как выглядит ваш прослушиватель событий, чтобы устранить неполадки, если ваш обработчик событий ведет себя не так, как ожидалось.
пример
Этот пример специфичен для 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.
Поскольку addEventListener
API не входит в спецификацию html5 (только on*
обработчики событий) ... было бы менее запутанно, если бы они on*
в своих примерах придерживались обработчиков событий стиля.