Oto kilka przykładów, które mogą pomóc ludziom lepiej zrozumieć i rozwiązywać problemy.
TL; DR
on*
procedury obsługi zdarzeń (np. onclick
atrybut w elemencie przycisku): zwraca false, aby anulować zdarzenie
addEventListener
jest innym API, wartości zwracane (np. false
) są ignorowane: użyj event.preventDefault()
.
onclick="<somejs>"
ma swoje własne potencjalne zamieszanie, ponieważ <somejs>
jest zawarty w treści funkcji onclick.
- Użyj
getEventListeners
interfejsu API przeglądarki devtools, aby zobaczyć, jak wygląda Twój detektor zdarzeń, aby rozwiązać problem, jeśli program obsługi zdarzeń nie działa zgodnie z oczekiwaniami.
Przykład
Ten przykład jest specyficzny dla click
zdarzenia z <a>
łączem ... ale można go uogólnić dla większości typów zdarzeń.
Mamy kotwicę (link) z klasą js-some-link-hook
, którą chcemy otworzyć modalnie i uniemożliwić nawigację po stronie.
Poniższe przykłady zostały uruchomione w Google Chrome (71) na MacOS Mojave.
Jedną z głównych pułapek jest założenie, że onclick=functionName
jest to takie samo zachowanie, jak używanieaddEventListener
Powiedzmy, że mamy znacznik kotwicy (link), który chcemy obsługiwać za pomocą javascript, gdy javascript jest włączony. Nie chcemy, aby przeglądarka podążała za linkiem po kliknięciu („zapobiegaj domyślnemu” zachowaniu).
<a href="https://www.example.com/url/to/go/to/when/no/javascript"
class="js-some-link-hook">click me!</a>
atrybut onclick
function eventHandler (event) {
alert('eventHandler ran');
return false;
}
function addEventListenerToElement () {
var link = document.querySelector('.js-some-link-hook');
link.setAttribute('onclick', eventHandler);
}
addEventListenerToElement();
Następnie uruchom w konsoli devtools przeglądarki:
var el = document.querySelector('a.js-some-link-hook'),
listener = getEventListeners(el).click[0].listener;
console.log(''+listener);
... i widzisz:
function onclick(event) {
function eventHandler (event) {alert('eventHandler ran'); return false;}
}
To w ogóle nie działa. Podczas korzystania onclick=
z funkcji obsługi funkcja jest opakowana w inną funkcję.
Możesz zobaczyć, że moja definicja funkcji jest dołączona, ale nie została wywołana, ponieważ określiłem odwołanie do funkcji bez wywoływania go. czyli musimy onclick="functionName()"
nie onclick="functionName"
upewnić się, functionName
jest uruchamiany, gdy element zostanie kliknięty.
Dalej widać, że nawet jeśli moja funkcja została wywołana, a moja funkcja zwróciłaby fałsz ... onclick
funkcja nie zwróciłaby tej fałszywej wartości ... która jest wymagana do „anulowania” zdarzenia.
W celu ustalenia tego, możemy ustawić onclick
się return myHandlerFunc();
co gwarantuje, że onclick
zwraca wartość return (false) z myHandlerFunc
.
Możesz również usunąć return false;
from myHandlerFunc
i zmienić na onclick
be, myHandlerFunc(); return false;
ale ma to mniej sensu, ponieważ prawdopodobnie chcesz zachować razem logikę w funkcji obsługi.
Zauważ, że podczas ustawiania za onclick
pomocą javascript , gdy ustawiasz onclick
bezpośrednio w html, a nie w javascript (jak moje przykłady), onclick
wartość atrybutu to string i wszystko działa. Jeśli ustawiasz onclick
za pomocą JavaScript, musisz zwrócić uwagę na typ. Jeśli powiesz, że element.setAttribute('onclick', myHandlerFunc())
myHandlerFunc
zostanie uruchomiony teraz, a wynik zostanie zapisany w atrybucie ... zamiast być uruchamiany po każdym kliknięciu. Zamiast tego powinieneś upewnić się, że wartość atrybutu jest ustawiona jako ciąg. element.setAttribute('onclick', 'return myHandlerFunc();')
Teraz, gdy widzimy, jak to działa, możemy zmodyfikować kod, aby robił, co chcemy. Dziwny przykład dla celów ilustracyjnych (nie używaj tego kodu):
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();
Widzisz, opakowaliśmy naszą definicję funkcji eventHandler w łańcuch. W szczególności: samowykonująca się funkcja z instrukcją return na początku.
Ponownie w konsoli Chrome Devtools:
var el = document.querySelector('a.js-some-link-hook'),
listener = getEventListeners(el).click[0].listener;
console.log(''+listener);
...przedstawia:
function onclick(event) {
return (function eventHandler (e) {
alert('eventHandler ran');
console.log(e);
return false;
})(event);
}
... więc tak, to powinno działać. Oczywiście, jeśli klikniemy link, otrzymamy alert i odrzucimy alert, strona nie będzie nigdzie nawigować ani odświeżać.
Jeszcze jedna uwaga na temat onclick
... Jeśli chcesz otrzymać i wykorzystać event
parametr w momencie zdarzenia, powinieneś zauważyć, że nazywa się on „zdarzenie”. Możesz uzyskać do tego dostęp w swoim programie obsługi za pomocą nazwy event
(dostępne w onclick
zakresie funkcji nadrzędnej ). Możesz też skonstruować procedurę obsługi tak, aby przyjmowała event
jako parametr (lepsze do testowania) ... np. onclick="return myEventHandler(event);"
Lub jak widać w poprzednim przykładzie.
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();
devtools przeglądarki:
var el = document.querySelector('a.js-some-link-hook'),
listener = getEventListeners(el).click[0].listener;
console.log(''+listener);
wynik:
function eventHandler (ev) {
alert('eventHandler ran');
console.log(ev);
return false;
}
Więc już widać różnicę. Nie addEventListener
jesteśmy opakowani w onclick
funkcję. Nasz program obsługi otrzymuje event
parametr bezpośrednio (więc możemy go nazwać, jak chcemy). Również nasz return false
jest tutaj na „najwyższym poziomie” i nie musimy się martwić o dodanie dodatkowej instrukcji zwrotu, jak w przypadku onclick
.
Więc wygląda na to, że powinno działać. Klikając w link otrzymujemy alert. Odrzuć alert, a strona przejdzie / odświeży się. tj. zdarzenie NIE zostało anulowane przez zwrócenie wartości false.
Jeśli sprawdzimy specyfikację (zobacz zasoby na dole), zobaczymy, że nasza funkcja wywołania zwrotnego / obsługi dla addEventListener nie obsługuje typu zwracanego. Możemy zwrócić, co chcemy, ale ponieważ nie jest to część interfejsu API / interfejsu przeglądarki, nie ma to żadnego efektu.
Rozwiązanie: używanie event.preventDefault()
zamiast 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();
devtools przeglądarki ...
var el = document.querySelector('a.js-some-link-hook'),
listener = getEventListeners(el).click[0].listener;
console.log(''+listener);
daje ...
function eventHandler (ev) {
ev.preventDefault();
alert('eventHandler ran');
}
...zgodnie z oczekiwaniami.
Testowanie ponownie:
- Kliknij łącze.
- Uzyskaj alert.
- Odrzuć alert.
- Nie dochodzi do nawigacji ani odświeżania strony ... a właśnie tego chcemy.
Więc z addEventListener
użyciem event.preventDefault()
jako zwracanie fałszu nic nie robi.
Zasoby
Specyfikacja HTML5 ( https://www.w3.org/TR/html5/webappapis.html#events ) myli rzeczy, ponieważ używają obu onclick
i addEventListener
w swoich przykładach i mówią, co następuje:
Algorytm przetwarzania obsługi zdarzeń dla programu obsługi zdarzeń H i obiektu zdarzenia E jest następujący:
...
- Przetwarzaj wartość zwracaną w następujący sposób:
...
Jeśli wartość zwracana jest logiczną fałszywą wartością Web IDL, anuluj zdarzenie.
Wydaje się więc sugerować, że return false
anuluje wydarzenie zarówno dla, jak addEventListener
i onclick
.
Ale jeśli spojrzysz na ich połączoną definicję event-handler
ciebie, zobaczysz:
Procedura obsługi zdarzeń ma nazwę, która zawsze zaczyna się od „on”, a po niej następuje nazwa zdarzenia, dla którego jest przeznaczona.
...
Procedury obsługi zdarzeń są ujawniane na jeden z dwóch sposobów.
Pierwszy sposób, wspólny dla wszystkich programów obsługi zdarzeń, to atrybut IDL programu obsługi zdarzeń.
Drugi sposób to atrybut zawartości modułu obsługi zdarzeń. W ten sposób są ujawniane programy obsługi zdarzeń w elementach HTML i niektóre programy obsługi zdarzeń w obiektach Window.
https://www.w3.org/TR/html5/webappapis.html#event-handler
Wydaje się więc, że return false
anulowanie zdarzenia naprawdę dotyczy tylko onclick
(lub ogólnie on*
) programów obsługi zdarzeń, a nie programów obsługi zdarzeń zarejestrowanych za pośrednictwem addEventListener
innego interfejsu API.
Ponieważ addEventListener
interfejs API nie jest objęty specyfikacją html5 (tylko on*
procedury obsługi zdarzeń) ... byłoby mniej zagmatwane, gdyby trzymali się on*
obsługi zdarzeń stylu w swoich przykładach.