event.preventDefault () проти повернення false (без jQuery)


84

Цікаво , якщо 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 () проти return false , навіть якщо обидва запитання мають майже однаковий заголовок.


Дублікат stackoverflow.com/questions/1357118/ ... Якщо ви прочитаєте запитання, ви помітите, що це загальна проблема JS, а не специфічна для jQuery. jQuery використовувався лише для того, щоб зробити приклад коду якомога коротшим / чистішим.
RaYell

13
@RaYell Ні, оскільки jQuery return falseповодиться інакше, ніж звичайний JavaScript. Більше того, на інше запитання немає жодної відповіді, яка б пояснювала різницю в простому JS (є лише коментар, який це пояснює, але важко знайти). Тому я думаю, що краще мати два різних запитання.
Oriol

Відповіді:


55

W3C Document Object Model Події Специфікація в п.1.3.1. Інтерфейси реєстрації подій стверджують, що handleEventв EventListener не повертається значення:

handleEvent Цей метод викликається щоразу, коли відбувається подія того типу, для якого був зареєстрований інтерфейс EventListener. [...] Без поверненого значення

під 1.2.4. У документі про скасування події також зазначено, що

Скасування здійснюється за допомогою виклику методу eventDeventDefault. Якщо один або кілька EventListeners викликають prevenDefault під час будь-якої фази потоку подій, дія за замовчуванням буде скасовано.

що має перешкодити вам використовувати будь-який ефект, який повернення 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 хибне значення, а потім скасувати подію "
Чарльз Л.

А після швидкого тестування в chrome і return, і event.preventDefault () не зупиняють розповсюдження. Кредит здебільшого @Oriol: Дивіться зупинку розповсюдження проти нормальної
Чарльз Л.

Ця скрипка порівнює поведінку stopPropagation(), preventDefault()і return false: jsfiddle.net/m1L6of9x . У сучасних браузерах два останні мають однакову поведінку.
Ерік Купманс,

5

Ось кілька прикладів, які можуть допомогти людям краще зрозуміти та вирішити свої проблеми.

TL; DR

  • on*обробники подій (наприклад, onclickатрибут елемента кнопки): повернути значення false, щоб скасувати подію
  • addEventListener- це інший API, повернені значення (наприклад false) ігноруються: use event.preventDefault().
  • onclick="<somejs>"має свою потенційну плутанину, тому що <somejs>вкладена в тіло функції onclick.
  • Використовуйте getEventListenersAPI devtools браузера, щоб побачити, як виглядає ваш прослуховувач подій, щоб усунути неполадки, якщо обробник подій не поводиться належним чином .

Приклад

Цей приклад є специфічним для 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();

Потім запустіть у консолі 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 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значенням атрибута є тип string і все працює. Якщо ви налаштовуєте 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 у рядок. Зокрема: самовиконання функції з оператором return на передній панелі.

Знову в консолі 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тут ми знаходимось на "верхньому рівні", і нам не доведеться турбуватися про додавання додаткового оператора повернення, як у 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()як повернення false нічого не робить.

Ресурси

Специфікація html5 ( https://www.w3.org/TR/html5/webappapis.html#events ) плутає речі, оскільки вони використовують і те, onclickі інше addEventListenerу своїх прикладах, і вони говорять таке:

Алгоритм обробки обробника подій для обробника подій H та об'єкта E подій є таким:

...

  1. Обробляти повернене значення таким чином:

...

Якщо повернене значення - логічне значення Web IDL, то скасуйте подію.

Отже, мається на увазі, що return falseскасовує подію як для, так addEventListenerі для onclick.

Але, якщо ви подивитесь на їх пов'язане визначення, event-handlerви побачите:

Обробник подій має ім'я, яке завжди починається з "увімкнено", а потім йде ім'я події, для якої воно призначене.

...

Обробники подій виставляються одним із двох способів.

Перший спосіб, загальний для всіх обробників подій, - це атрибут IDL обробника подій.

Другий спосіб - це атрибут вмісту обробника подій. Обробники подій для елементів HTML та деякі обробники подій для об'єктів Window виставляються таким чином.

https://www.w3.org/TR/html5/webappapis.html#event-handler

Отже, здається, що return falseскасування події насправді стосується лише обробників подій onclick(або взагалі on*), а не обробників подій, зареєстрованих через addEventListenerякі має інший API.

Оскільки addEventListenerAPI не охоплюється специфікацією html5 (лише on*обробники подій) ... було б менш заплутано, якби вони дотримувались on*обробників подій стилю у своїх прикладах.


-2

Різниця між профілем запобігання замовчуванню, зупинкою перенесення, поверненням помилки

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

Дія за замовчуванням - Дія на стороні сервера, коли піднімається подія управління.

Припустимо, у нас є контроль div, і всередині нього ми маємо кнопку. Отже, div - це батьківський контроль кнопки. У нас є клік на стороні клієнта та клік на стороні сервера. Також у нас є подія кліку на стороні клієнта div.

Після події натискання кнопки на стороні клієнта ми можемо керувати діями батьківського контролю та коду на стороні сервера, використовуючи такі три способи:

  • return false- Це дозволяє лише клієнтську подію елемента керування. Подія на стороні сервера та на стороні клієнта батьківського контролю не запускаються.

  • preventDefault()- Це дозволяє керувати подіями на стороні клієнта та батьківським контролем. Подія на стороні сервера, тобто. Дія елемента керування за замовчуванням не запускається.

  • stopPropogation()- Це дозволить на стороні клієнта, а також на стороні сервера керування. Клієнтська сторона події контролю не дозволяється.


21
Ви помиляєтесь, return falseне зупиняєте розповсюдження, тому батьківський контроль ІС спрацьовує ( демо ). Більше того, я не впевнений, що ви маєте на увазі під " подією натискання на стороні сервера ".
Oriol

6
@ Початківці, проігноруйте цю відповідь.
плов

4
Що це за нісенітниця про події на стороні сервера? -1
Марк Амері

Я думаю, що серверні речі думають про ASP, де ви можете обробляти події на сервері.
Ендрю

5
Немає "сторони сервера", коли мова йде про JavaScript та події.
rawpower

-12

return falseпризначений лише для IE, event.preventDefault()підтримується chrome, ff ... сучасними браузерами


9
Але у Firefox return falseпрацює, як event.preventDefault()коли обробник події додається за старою моделлю
Oriol
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.