Мой вопрос касается только простого javascript, а не jQuery, поэтому, пожалуйста, не помечайте его как дубликат event.preventDefault() и возвращайте false, даже если оба вопроса имеют почти одинаковый заголовок.
Ответ 1
Спецификация событий объектной модели документа W3C в 1.3.1. Интерфейсы регистрации событий указывают, что handleEvent
в EventListener не имеет возвращаемого значения:
handleEvent
Этот метод вызывается всякий раз, когда происходит событие того типа, для которого был зарегистрирован интерфейс EventListener. [...] Нет возвращаемого значения
под 1.2.4. Событие отмены документа также гласит, что
Отмена осуществляется путем вызова метода Event protectDefault. Если один или несколько EventListeners вызовут protectDefault во время любой фазы потока событий, действие по умолчанию будет отменено.
что должно препятствовать вам использовать любой эффект, который может иметь возвращение true/false в любом браузере, и использовать event.preventDefault()
.
Обновить
Спецификация HTML5 фактически определяет, как обрабатывать возвращаемое значение иначе. Раздел 7.1.5.1 спецификации HTML гласит, что
Если возвращаемое значение является логическим ложным значением WebIDL, отмените событие.
для всего, кроме события "наведения мыши".
Заключение
Я по-прежнему рекомендую использовать event.preventDefault()
в большинстве проектов, так как вы будете совместимы со старой спецификацией и, следовательно, со старыми браузерами. Только если вам нужно только поддерживать передовые браузеры, возвращать false для отмены можно.
Ответ 2
Вот несколько примеров, которые могут помочь людям лучше понять и устранить свои проблемы.
TL; DR
- Обработчики событий
on*
(например, атрибут onclick
для элемента кнопки): вернуть false, чтобы отменить событие
addEventListener
- это другой API, возвращаемые значения (например, false
) игнорируются: используйте event.preventDefault()
.
onclick="<somejs>"
имеет свою потенциальную путаницу, потому что <somejs>
заключен в тело функции onclick.
- Используйте API браузера devtools
getEventListeners
, чтобы увидеть, как выглядит ваш прослушиватель событий для устранения неполадок, если ваш обработчик событий работает не так, как ожидалось.
Пример
Этот пример относится к событию click
со ссылкой <a>
... но может быть обобщен для большинства типов событий.
У нас есть якорь (ссылка) с классом js-some-link-hook
, который мы хотим открыть модально и предотвратить любую навигацию по страницам.
Приведенные ниже примеры были запущены в Google Chrome (71) на MacOS Mojave.
Одна большая ловушка предполагает, что onclick=functionName
такое же поведение, как и при использовании addEventListener
атрибут onclick
function eventHandler (event) {
// want to prevent link navigation
alert('eventHandler ran');
return false;
}
function addEventListenerToElement () {
var link = document.querySelector('.js-some-link-hook');
link.setAttribute('onclick', eventHandler);
}
addEventListenerToElement();
Затем запустите в браузере консоль devtools:
var el = document.querySelector('a.js-some-link-hook'),
listener = getEventListeners(el).click[0].listener;
console.log(''+listener); // to avoid truncation of output
... и вы видите:
function onclick(event) {
function t(n){return alert("eventHandler ran"),!1}
}
Это не работает вообще. При использовании onclick=
ваша функция-обработчик оборачивается другой функцией. В этом случае вы можете видеть, что мое определение функции включено, но не вызвано, потому что я указал ссылку на функцию, не вызывая ее. Кроме того, вы можете видеть, что даже если бы моя функция была вызвана и моя функция вернула false... функция onclick не вернула бы это ложное значение... которое требуется для "отмены" события. Нам действительно нужно, чтобы return myHandlerFunc();
был включен в функцию onclick, чтобы все работало.
Теперь, когда мы видим, как это работает, мы можем изменить код, чтобы сделать все, что мы хотим. Странный пример для иллюстрации (не используйте этот код):
function eventHandler (event) {
// want to prevent link navigation
alert('eventHandler ran');
return false;
}
function addEventListenerToElement () {
var link = document.querySelector('.js-some-link-hook');
link.setAttribute('onclick', 'return ('+eventHandler+')();');
}
addEventListenerToElement();
Вы видите, что мы завернули определение нашей функции eventHandler в строку. В частности: самовыполняющаяся функция с оператором возврата в начале.
Снова в консоли chrome devtools:
var el = document.querySelector('a.js-some-link-hook'),
listener = getEventListeners(el).click[0].listener;
console.log(''+listener); // to avoid truncation of output
... показывает:
function onclick(event) {
return (function t(e){return alert("eventHandler ran"),!1})();
}
... так что да, это должно сработать. Наш return false
(!1
из-за минификации запущен, извините). Конечно же, если мы нажмем на ссылку, мы получим предупреждение и отклоним предупреждение, страница никуда не перемещается и не обновляется.
addEventListener
function eventHandler (event) {
// want to prevent link navigation
alert('eventHandler ran');
return false;
}
function addEventListenerToElement () {
var link = document.querySelector('.js-some-link-hook');
link.addEventListener('click', eventHandler, false);
}
addEventListenerToElement();
браузер devtools:
var el = document.querySelector('a.js-some-link-hook'),
listener = getEventListeners(el).click[0].listener;
console.log(''+listener); // to avoid truncation of output
результат:
function e(n){return alert("eventHandler ran"),!1}
Итак, вы уже можете увидеть разницу. Мы не обернуты в функцию onclick. Таким образом, наш return false
(return !1
из-за минимизации) находится здесь на верхнем уровне, и нам не нужно беспокоиться о добавлении дополнительного оператора возврата, как раньше.
Похоже, это должно работать. Нажав на ссылку, мы получим оповещение. Отключите предупреждение, и страница будет перемещаться/обновляться. то есть событие НЕ было отменено путем возврата false.
Если мы посмотрим на спецификацию (см. ресурсы внизу), мы увидим, что наша функция обратного вызова/обработчика для addEventListener не поддерживает тип возвращаемого значения. Мы можем вернуть все, что захотим, но поскольку он не является частью интерфейса, он не оказывает никакого влияния.
Решение: использовать event.preventDefault()
вместо return false;
...
function eventHandler (event) {
// want to prevent link navigation
event.preventDefault();
alert('eventHandler ran');
}
function addEventListenerToElement () {
var link = document.querySelector('.js-some-link-hook');
link.addEventListener('click', eventHandler, false);
}
addEventListenerToElement();
браузер devtools...
var el = document.querySelector('a.js-some-link-hook'),
listener = getEventListeners(el).click[0].listener;
console.log(''+listener); // to avoid truncation of output
дает...
function n(e){e.preventDefault(),alert("eventHandler ran")}
... как и ожидалось.
Тестирование: получить оповещение. Уволить оповещение. Нет навигации по страницам или обновления... чего мы и хотим.
Ресурсы
Спецификация 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. Так как API addEventListener не охватывается спецификацией html5 и только обработчиками событий on*
... было бы менее запутанным, если бы они придерживались этого в своих примерах и специально выявляли разницу.