Event.preventDefault() vs. return false (нет jQuery)

Я задавался вопросом, были ли event.preventDefault() и return false одинаковыми.

Я сделал несколько тестов, и кажется, что

  • Если обработчик события добавляется с использованием старой модели, например

    elem.onclick = function(){
        return false;
    };
    

    Затем return false предотвращает действие по умолчанию, такое как event.preventDefault().

  • Если обработчик события добавляется с использованием, например, addEventListener

    elem.addEventListener(
        'click',
        function(e){
            return false;
        },
        false
    );
    

    Тогда return false не препятствует действию по умолчанию.

Все ли браузеры ведут себя так?

Есть ли больше различий между event.preventDefault() и return false?

Где я могу найти некоторую документацию (я не мог в MDN) о return false поведения, подобного event.preventDefault() в некоторых случаях?


Мой вопрос касается только простого 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 выглядит следующим образом:

...

  1. Обработайте возвращаемое значение следующим образом:

...

Если возвращаемое значение является логическим ложным значением 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*... было бы менее запутанным, если бы они придерживались этого в своих примерах и специально выявляли разницу.

Ответ 3

Разница между preventDefault, stopPropogation, return false

Table Showing Difference

Действие по умолчанию - действие на стороне сервера при активизации события управления.

Предположим, что у нас есть div-управление, и внутри него есть кнопка. Таким образом, div является родительским элементом управления кнопкой. У нас есть клик и клик на стороне сервера. Также у нас есть событие клика на стороне клиента.

В момент нажатия кнопки на стороне клиента мы можем управлять действиями родительского элемента управления и кода на стороне сервера, используя следующие три способа:

  • return false - Это разрешает только событие на стороне клиента. Событие стороне сервера и клиентская сторона родительского элемента управления не запускаются.

  • preventDefault() - Это позволяет управлять событиями на стороне клиента и его родительским элементом управления. Событие на стороне сервера, т.е. По умолчанию действие элемента управления не запускается.

  • stopPropogation() - Это позволяет стороне клиента, а также событиям на стороне сервера. Событие стороны клиента не указано.

Ответ 4

return false предназначен только для IE, event.preventDefault() поддерживается хром, ff... современными браузерами