Ось кілька прикладів, які можуть допомогти людям краще зрозуміти та вирішити свої проблеми.
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) {
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);
... і ви бачите:
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) {
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);
... показує:
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тут ми знаходимось на "верхньому рівні", і нам не доведеться турбуватися про додавання додаткового оператора повернення, як у 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()як повернення false нічого не робить.
Ресурси
Специфікація html5 ( https://www.w3.org/TR/html5/webappapis.html#events ) плутає речі, оскільки вони використовують і те, onclickі інше addEventListenerу своїх прикладах, і вони говорять таке:
Алгоритм обробки обробника подій для обробника подій H та об'єкта E подій є таким:
...
- Обробляти повернене значення таким чином:
...
Якщо повернене значення - логічне значення 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*обробників подій стилю у своїх прикладах.