Ось кілька прикладів, які можуть допомогти людям краще зрозуміти та вирішити свої проблеми.
TL; DR
on*
обробники подій (наприклад, onclick
атрибут елемента кнопки): повернути значення false, щоб скасувати подію
addEventListener
- це інший API, повернені значення (наприклад false
) ігноруються: use event.preventDefault()
.
onclick="<somejs>"
має свою потенційну плутанину, тому що <somejs>
вкладена в тіло функції onclick.
- Використовуйте
getEventListeners
API 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.
Оскільки addEventListener
API не охоплюється специфікацією html5 (лише on*
обробники подій) ... було б менш заплутано, якби вони дотримувались on*
обробників подій стилю у своїх прикладах.