event.preventDefault () vs. return false (bez jQuery)

84

Zastanawiałam się, czy event.preventDefault()i return falsebyły takie same.

Zrobiłem kilka testów i wygląda na to

  • Jeśli na przykład program obsługi zdarzeń zostanie dodany przy użyciu starego modelu

    elem.onclick = function(){
        return false;
    };
    

    Następnie return falsezapobiega domyślnej akcji, takiej jak event.preventDefault().

  • Jeśli program obsługi zdarzeń zostanie dodany przy użyciu addEventListener, na przykład

    elem.addEventListener(
        'click',
        function(e){
            return false;
        },
        false
    );
    

    Wtedy return falsenie zapobiega domyślnej akcji.

Czy wszystkie przeglądarki zachowują się w ten sposób?

Czy jest więcej różnic między event.preventDefault()i return false?

Gdzie mogę znaleźć dokumentację (której nie mogłem w MDN) na temat return falsezachowania się event.preventDefault()w niektórych przypadkach?


Moje pytanie dotyczy tylko zwykłego javascript, a nie jQuery, więc proszę nie oznaczać go jako duplikatu zdarzenia event.preventDefault () vs. return false , nawet jeśli oba pytania mają prawie ten sam tytuł.

Oriol
źródło
Duplikat stackoverflow.com/questions/1357118/… Jeśli przeczytasz pytanie, zauważysz, że jest to ogólny problem JS, a nie ten związany z jQuery. jQuery był używany tylko po to, aby przykładowy kod był tak krótki / czysty, jak to tylko możliwe.
RaYell
13
@RaYell Nie, ponieważ jQuery return falsezachowuje się inaczej niż zwykły JavaScript. Co więcej, na drugie pytanie nie ma odpowiedzi wyjaśniającej różnicę w zwykłym JS (jest tylko komentarz, który to wyjaśnia, ale jest trudny do znalezienia). Myślę więc, że lepiej mieć dwa różne pytania.
Oriol

Odpowiedzi:

55

Object model Wydarzenia Specyfikacja W3C Dokument w 1.3.1. Interfejsy rejestracji zdarzeń stwierdzają, że handleEventw EventListener nie ma zwracanej wartości:

handleEvent Ta metoda jest wywoływana za każdym razem, gdy wystąpi zdarzenie typu, dla którego zarejestrowano interfejs EventListener. [...] Brak wartości zwracanej

pod 1.2.4. Anulowanie zdarzenia dokument również to stwierdza

Anulowanie jest realizowane przez wywołanie metody prevDefault zdarzenia. Jeśli co najmniej jedna funkcja EventListeners wywoła zapobiecDefault podczas dowolnej fazy przepływu zdarzenia, akcja domyślna zostanie anulowana.

co powinno zniechęcać Cię do używania jakiegokolwiek efektu, jaki może mieć zwrócenie wartości prawda / fałsz w dowolnej przeglądarce i użyciu event.preventDefault().

Aktualizacja

Specyfikacja HTML5 w rzeczywistości określa sposób traktowania wartości zwracanej inaczej. Sekcja 7.1.5.1 specyfikacji HTML stwierdza, że

Jeśli wartość zwracana jest logiczną fałszywą wartością WebIDL, anuluj zdarzenie.

za wszystko oprócz zdarzenia „mouseover”.

Wniosek

Nadal zalecałbym używanie event.preventDefault()w większości projektów, ponieważ będziesz kompatybilny ze starą specyfikacją, a tym samym ze starszymi przeglądarkami. Tylko jeśli potrzebujesz tylko obsługi najnowocześniejszych przeglądarek, zwracanie wartości false w celu anulowania jest w porządku.

Thorben Croisé
źródło
2
To łącze zostało napisane w 2000 roku. Specyfikacja HTML5: w3.org/TR/html5/webappapis.html#event-handler-attributes wygląda tak, jakby obsługiwała wartości zwracane dla wielu zdarzeń (bez użycia wskaźnika myszy): „Jeśli wartość zwracana jest wartością logiczną WebIDL wartość fałszywa, a następnie anuluj wydarzenie ”
Charles L.
Z niektórych szybkich testów w Chrome wynika, że ​​zarówno return false, jak i event.preventDefault () nie zatrzymują propagacji. Kredyt głównie dla @Oriol: Zobacz propagację zatrzymania w porównaniu z normalnymi
Charles L.
To skrzypce porównuje zachowanie stopPropagation(), preventDefault()oraz return false: jsfiddle.net/m1L6of9x . W nowoczesnych przeglądarkach te dwie ostatnie zachowują się tak samo.
Erik Koopmans
5

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. onclickatrybut w elemencie przycisku): zwraca false, aby anulować zdarzenie
  • addEventListenerjest 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 getEventListenersinterfejsu 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 clickzdarzenia 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=functionNamejest 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) {
    // 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();

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); // to avoid truncation of output

... 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ę, functionNamejest 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 ... onclickfunkcja nie zwróciłaby tej fałszywej wartości ... która jest wymagana do „anulowania” zdarzenia.

W celu ustalenia tego, możemy ustawić onclicksię return myHandlerFunc();co gwarantuje, że onclickzwraca wartość return (false) z myHandlerFunc.

Możesz również usunąć return false;from myHandlerFunci zmienić na onclickbe, myHandlerFunc(); return false;ale ma to mniej sensu, ponieważ prawdopodobnie chcesz zachować razem logikę w funkcji obsługi.

Zauważ, że podczas ustawiania za onclickpomocą javascript , gdy ustawiasz onclickbezpośrednio w html, a nie w javascript (jak moje przykłady), onclickwartość atrybutu to string i wszystko działa. Jeśli ustawiasz onclickza pomocą JavaScript, musisz zwrócić uwagę na typ. Jeśli powiesz, że element.setAttribute('onclick', myHandlerFunc()) myHandlerFunczostanie 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) {
    // 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();

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); // to avoid truncation of output

...przedstawia:

function onclick(event) {
return (function eventHandler (e) {
        // want to prevent link navigation
        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ć eventparametr 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 onclickzakresie funkcji nadrzędnej ). Możesz też skonstruować procedurę obsługi tak, aby przyjmowała eventjako parametr (lepsze do testowania) ... np. onclick="return myEventHandler(event);"Lub jak widać w poprzednim przykładzie.

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

devtools przeglądarki:

var el = document.querySelector('a.js-some-link-hook'),
        listener = getEventListeners(el).click[0].listener;
console.log(''+listener); // to avoid truncation of output

wynik:

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

Więc już widać różnicę. Nie addEventListenerjesteśmy opakowani w onclickfunkcję. Nasz program obsługi otrzymuje eventparametr bezpośrednio (więc możemy go nazwać, jak chcemy). Również nasz return falsejest 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) {
    // 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();

devtools przeglądarki ...

var el = document.querySelector('a.js-some-link-hook'),
        listener = getEventListeners(el).click[0].listener;
console.log(''+listener); // to avoid truncation of output

daje ...

function eventHandler (ev) {
    // want to prevent link navigation
    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 addEventListeneruż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 onclicki addEventListenerw 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:

...

  1. 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 falseanuluje wydarzenie zarówno dla, jak addEventListeneri onclick.

Ale jeśli spojrzysz na ich połączoną definicję event-handlerciebie, 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 falseanulowanie 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 addEventListenerinnego interfejsu API.

Ponieważ addEventListenerinterfejs 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.

mattpr
źródło
-2

Różnica między allowDefault, stopPropogation, return false

Tabela pokazująca różnicę

Akcja domyślna - akcja po stronie serwera po wywołaniu zdarzenia sterowania.

Załóżmy, że mamy kontrolkę DIV i wewnątrz niej znajduje się przycisk. Zatem div jest nadrzędną kontrolą przycisku. Mamy kliknięcie po stronie klienta i zdarzenie kliknięcia przycisku po stronie serwera. Mamy również zdarzenie kliknięcia div po stronie klienta.

W przypadku kliknięcia przycisku po stronie klienta możemy kontrolować działania kontroli rodzicielskiej i kodu po stronie serwera na trzy sposoby:

  • return false- To zezwala tylko na zdarzenie kontroli po stronie klienta. Zdarzenie po stronie serwera i zdarzenie po stronie klienta formantu nadrzędnego nie jest wyzwalane.

  • preventDefault()- Pozwala to na zdarzenie kontroli po stronie klienta i kontrolę nadrzędną. Zdarzenie po stronie serwera, tj. Domyślna akcja formantu nie jest uruchamiana.

  • stopPropogation()- Pozwala to na zdarzenie kontroli po stronie klienta oraz po stronie serwera. Zdarzenie po stronie klienta dotyczące formantu nie jest dozwolone.

Rahul Shinde
źródło
21
Mylisz się, return falsenie zatrzymujesz propagacji, więc uruchamiana jest kontrola rodzicielska ( wersja demonstracyjna ). Co więcej, nie jestem pewien, co masz na myśli mówiąc o „ zdarzeniu kliknięcia po stronie serwera ”.
Oriol
6
@Beginners, zignoruj ​​tę odpowiedź.
pilau
4
Co to za bzdury związane ze zdarzeniami po stronie serwera? -1
Mark Amery,
Myślę, że po stronie serwera chodzi o ASP, w której można obsługiwać zdarzenia na serwerze.
Andrew
5
W przypadku JavaScript i zdarzeń nie ma „po stronie serwera”.
rawpower
-12

return falsejest tylko dla IE, event.preventDefault()jest obsługiwany przez chrome, ff ... nowoczesne przeglądarki

ppy
źródło
9
Ale w przeglądarce Firefox return falsedziała tak, jak event.preventDefault()wtedy, gdy program obsługi zdarzeń jest dodawany przy użyciu starego modelu
Oriol,