event.preventDefault () vs. return false (без jQuery)

85

Я задавался вопросом, были ли 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 () vs. return false , даже если оба вопроса имеют почти одинаковый заголовок.

Ориол
источник
Дубликат stackoverflow.com/questions/1357118/… Если вы прочитаете вопрос, то заметите, что это общая проблема JS, а не специфическая для jQuery. jQuery использовался только для того, чтобы сделать пример кода как можно более коротким / чистым.
RaYell 08
14
@RaYell Нет, потому что jQuery return falseведет себя иначе, чем простой JavaScript. Более того, на другой вопрос нет ответа, объясняющего разницу в простом JS (есть только комментарий, который это объясняет, но его трудно найти). Поэтому я считаю, что лучше задать два разных вопроса.
Oriol

Ответы:

55

W3C Document Object Model События Спецификация в п.1.3.1. В интерфейсах регистрации событий указано, что handleEventв EventListener нет возвращаемого значения:

handleEvent Этот метод вызывается всякий раз, когда происходит событие того типа, для которого был зарегистрирован интерфейс EventListener. [...] Нет возвращаемого значения

под 1.2.4. Отмена события в документе также говорится, что

Отмена выполняется путем вызова метода preventDefault события. Если один или несколько EventListeners вызывают preventDefault во время любой фазы потока событий, действие по умолчанию будет отменено.

что должно отговорить вас от использования какого-либо эффекта, который возврат true / false может иметь в любом браузере и использовании event.preventDefault().

Обновить

Спецификация HTML5 фактически определяет, как обрабатывать возвращаемое значение по-другому. В разделе 7.1.5.1 спецификации HTML говорится, что

Если возвращаемое значение - логическое ложное значение WebIDL, событие отменяется.

для всего, кроме события "наведения курсора".

Заключение

Я по-прежнему рекомендую использовать event.preventDefault()в большинстве проектов, поскольку вы будете совместимы со старой спецификацией и, следовательно, со старыми браузерами. Только если вам нужно поддерживать только самые современные браузеры, можно вернуть false для отмены.

Торбен Круазе
источник
2
Эта ссылка была написана в 2000 году. Спецификация HTML5: w3.org/TR/html5/webappapis.html#event-handler-attributes выглядит так, как будто она обрабатывает возвращаемые значения для многих событий (не при наведении курсора мыши): «Если возвращаемое значение является логическим значением WebIDL значение false, затем отмените мероприятие »
Чарльз Л.
И из некоторого быстрого тестирования в chrome оба возвращают false и event.preventDefault () не останавливают распространение. Кредит в основном принадлежит @Oriol: см. Остановку распространения по сравнению с нормальным
Чарльз Л.
Эта скрипка сравнивает поведение stopPropagation(), preventDefault()и return false: jsfiddle.net/m1L6of9x . В современных браузерах последние два ведут себя одинаково.
Эрик Купманс,
6

Вот несколько примеров, которые могут помочь людям лучше понять свои проблемы и устранить их.

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) {
    // 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();

Затем запустите в консоли разработчика браузера:

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 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) {
    // want to prevent link navigation
    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); // to avoid truncation of output

... показывает:

function onclick(event) {
return (function eventHandler (e) {
        // want to prevent link navigation
        alert('eventHandler ran');
        console.log(e);
        return false;
    })(event);
}

... так что да, это должно сработать. Разумеется, если мы нажмем на ссылку, мы получим предупреждение и, отклонив предупреждение, страница не будет перемещаться и не обновится.

Еще одно примечание о onclick... Если вы хотите получить и использовать eventпараметр во время события, вы должны отметить, что он называется «событие». Вы можете получить к нему доступ в своем обработчике, используя имя event(доступно через область родительской onclickфункции). Или вы можете eventсоздать свой обработчик, который будет принимать его в качестве параметра (лучше для тестирования) ... например, onclick="return myEventHandler(event);"или как вы видите в предыдущем примере.

addEventListener

function eventHandler (ev) {
    // want to prevent link navigation
    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); // to avoid truncation of output

результат:

function eventHandler (ev) {
    // want to prevent link navigation
    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) {
    // want to prevent link navigation
    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); // to avoid truncation of output

дает ...

function eventHandler (ev) {
    // want to prevent link navigation
    ev.preventDefault();
    alert('eventHandler ran');
}

...как и ожидалось.

Снова тестирование:

  • Щелкните ссылку.
  • Получите оповещение.
  • Отключить оповещение.
  • Никакой навигации по страницам или обновления не происходит ... это то, что мы хотим.

Таким образом, при addEventListenerиспользовании event.preventDefault()as возврат false ничего не делает.

Ресурсы

Спецификация 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.

Поскольку addEventListenerAPI не входит в спецификацию html5 (только on*обработчики событий) ... было бы менее запутанно, если бы они on*в своих примерах придерживались обработчиков событий стиля.

матпр
источник
-2

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

Таблица, показывающая разницу

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

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

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

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

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

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

Рахул Шинде
источник
21
Вы ошибаетесь, return falseраспространение не прекращается, поэтому родительский контроль запускается ( демонстрация ). Более того, я не совсем понимаю, что вы имеете в виду под « событием щелчка на стороне сервера ».
Oriol
6
@ Новички, проигнорируйте этот ответ.
плов
4
Что это за чушь про серверные события? -1
Марк Эмери
Я думаю, что серверная часть думает об ASP, где вы можете обрабатывать события на сервере.
Эндрю
5
Говоря о JavaScript и событиях, не существует «серверной стороны».
rawpower 07
-12

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

ppy
источник
10
Но в Firefox return falseработает так же, как event.preventDefault()если бы обработчик событий был добавлен по старой модели
Ориол