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


85

Mi chiedevo se event.preventDefault()e return falsefossero la stessa cosa.

Ho fatto alcuni test e sembra che

  • Se il gestore eventi viene aggiunto utilizzando il vecchio modello, ad esempio

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

    Quindi, return falseimpedisce l'azione predefinita, come event.preventDefault().

  • Se il gestore eventi viene aggiunto utilizzando addEventListener, ad esempio

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

    Quindi, return falsenon impedisce l'azione predefinita.

Tutti i browser si comportano in questo modo?

Ci sono più differenze tra event.preventDefault()e return false?

Dove posso trovare della documentazione (non potrei in MDN) su return falsecome comportarmi event.preventDefault()in alcuni casi?


La mia domanda riguarda solo javascript semplice, non jQuery, quindi per favore non contrassegnarlo come un duplicato di event.preventDefault () vs. return false , anche se entrambe le domande hanno quasi lo stesso titolo.


Duplicato di stackoverflow.com/questions/1357118/… Se leggi la domanda noterai che si tratta di un problema JS generico e non specifico di jQuery. jQuery è stato utilizzato solo per rendere il codice di esempio il più breve / pulito possibile.
RaYell

14
@RaYell No, perché jQuery si return falsecomporta in modo diverso dal semplice JavaScript. Inoltre, l'altra domanda non ha alcuna risposta che spieghi la differenza nel semplice JS (c'è solo un commento che lo spiega, ma è difficile da trovare). Quindi penso che sia meglio avere due domande diverse.
Oriol

Risposte:


55

La specifica degli eventi del modello a oggetti del documento W3C in 1.3.1. Le interfacce di registrazione degli eventi indicano che handleEventin EventListener non ha alcun valore di ritorno:

handleEvent Questo metodo viene chiamato ogni volta che si verifica un evento del tipo per il quale è stata registrata l'interfaccia EventListener. [...] Nessun valore di ritorno

sotto 1.2.4. Annullamento dell'evento il documento lo afferma anche

L'annullamento viene eseguito chiamando il metodo preventDefault dell'evento. Se uno o più EventListeners chiamano preventDefault durante qualsiasi fase del flusso di eventi, l'azione predefinita verrà annullata.

che dovrebbe scoraggiare l'utilizzo di qualsiasi effetto che la restituzione di true / false potrebbe avere in qualsiasi browser e utilizzo event.preventDefault().

Aggiornare

La specifica HTML5 specifica effettivamente come trattare un valore restituito in modo diverso. La sezione 7.1.5.1 delle specifiche HTML afferma che

Se il valore restituito è un valore falso booleano WebIDL, annullare l'evento.

per tutto tranne l'evento "mouseover".

Conclusione

Consiglierei comunque di usarlo event.preventDefault()nella maggior parte dei progetti poiché sarai compatibile con la vecchia specifica e quindi con i browser meno recenti. Solo se è necessario supportare solo browser all'avanguardia, la restituzione di false per annullare va bene.


2
Questo collegamento è stato scritto nel 2000. La specifica HTML5: w3.org/TR/html5/webappapis.html#event-handler-attributes sembra che gestisca i valori di ritorno per molti eventi (non il passaggio del mouse): "Se il valore di ritorno è un booleano WebIDL valore falso, quindi annulla l'evento "
Charles L.

E da alcuni rapidi test in Chrome, sia return false che event.preventDefault () non interrompono la propagazione. Ringraziamo principalmente @Oriol: vedi stop propagation vs. normale
Charles L.

Questo violino a confronto il comportamento dei stopPropagation(), preventDefault()e return false: jsfiddle.net/m1L6of9x . Sui browser moderni, gli ultimi due hanno lo stesso comportamento.
Erik Koopmans

6

Di seguito sono riportati alcuni esempi che potrebbero aiutare le persone a comprendere e risolvere meglio i propri problemi.

TL; DR

  • on*gestori di eventi (ad es. onclickattributo su un elemento pulsante): restituire false per annullare l'evento
  • addEventListenerè un'API diversa, i valori di ritorno (ad esempio false) vengono ignorati: use event.preventDefault().
  • onclick="<somejs>"ha la sua potenziale confusione perché <somejs>è avvolto nel corpo di una funzione onclick.
  • Utilizza l' getEventListenersAPI devtools del browser per vedere come appare il tuo listener di eventi per risolvere i problemi se il tuo gestore di eventi non si comporta come previsto.

Esempio

Questo esempio è specifico per l' clickevento con un <a>collegamento ... ma può essere generalizzato per la maggior parte dei tipi di evento.

Abbiamo un'ancora (collegamento) con la classe js-some-link-hookche vogliamo aprire come modale e impedire che avvenga la navigazione della pagina.

Gli esempi seguenti sono stati eseguiti in Google Chrome (71) su MacOS Mojave.

Uno dei principali problemi è presumere che onclick=functionNamesia lo stesso comportamento dell'usoaddEventListener

Supponiamo di avere un anchor tag (link) che vogliamo gestire con javascript quando javascript è abilitato. Non vogliamo che il browser segua il collegamento quando viene cliccato (comportamento "Impedisci predefinito").

<a href="https://www.example.com/url/to/go/to/when/no/javascript"
   class="js-some-link-hook">click me!</a>

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

Quindi esegui nella console devtools del browser:

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

... e vedi:

function onclick(event) {
function eventHandler (event) {alert('eventHandler ran'); return false;}
}

Questo non funziona affatto. Quando si utilizza onclick=la funzione del gestore è racchiusa in un'altra funzione.

Puoi vedere che la mia definizione di funzione è inclusa ma non chiamata perché ho specificato il riferimento alla funzione senza richiamarlo. vale a dire che dobbiamo onclick="functionName()"non onclick="functionName"fare in modo functionNameviene eseguito quando l'elemento viene cliccato.

Inoltre puoi vedere che anche se la mia funzione è stata chiamata e la mia funzione ha restituito false ... la onclickfunzione non restituirebbe quel valore falso ... che è richiesto per 'annullare' l'evento.

Per risolvere questo problema, possiamo impostare onclicksu be return myHandlerFunc();che garantisce che onclickrestituisca il valore restituito (false) da myHandlerFunc.

Potresti anche rimuovere return false;da myHandlerFunce modificare onclickin essere, myHandlerFunc(); return false;ma questo ha meno senso poiché probabilmente vorrai mantenere la logica insieme nella tua funzione gestore.

Nota quando si imposta onclickcon javascript , quando si sta impostando onclickdirettamente in html piuttosto che con javascript (come i miei esempi), il onclickvalore dell'attributo è di tipo stringa e tutto funziona. Se stai impostando onclickusando javascript, devi prestare attenzione al tipo. Se dici element.setAttribute('onclick', myHandlerFunc()) myHandlerFuncche verrà eseguito in questo momento e il risultato verrà memorizzato nell'attributo ... anziché essere eseguito a ogni clic. Invece dovresti assicurarti che il valore dell'attributo sia impostato come una stringa. element.setAttribute('onclick', 'return myHandlerFunc();')

Ora che vediamo come funziona, possiamo modificare il codice per fare quello che vogliamo. Strano esempio a scopo illustrativo (non utilizzare questo codice):

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

Vedete, abbiamo racchiuso la nostra definizione di funzione eventHandler in una stringa. Nello specifico: una funzione autoeseguibile con un'istruzione return in primo piano.

Di nuovo nella console di 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

...Spettacoli:

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

... quindi sì, dovrebbe funzionare. Abbastanza sicuro, se clicchiamo sul collegamento otteniamo l'avviso e chiudendo l'avviso la pagina non si sposta da nessuna parte né si aggiorna.

Un'altra nota su onclick... Se vuoi ricevere e utilizzare il eventparametro al momento dell'evento, dovresti notare che si chiama "evento". È possibile accedervi all'interno del gestore utilizzando il nome event(disponibile tramite l' onclickambito della funzione padre ). Oppure puoi costruire il tuo gestore da prendere eventcome parametro (meglio per i test) ... ad es. onclick="return myEventHandler(event);"O come vedi nell'esempio precedente.

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

strumenti di sviluppo del browser:

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

risultato:

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

Quindi puoi già vedere la differenza. Con addEventListenernon siamo avvolti in una onclickfunzione. Il nostro gestore riceve eventdirettamente il parametro (e quindi possiamo chiamarlo come vogliamo). Inoltre il nostro return falseè al "livello più alto" qui e non dobbiamo preoccuparci di aggiungere un'istruzione di ritorno extra come con onclick.

Quindi sembra che dovrebbe funzionare. Cliccando sul link otteniamo l'avviso. Ignora l'avviso e la pagina naviga / si aggiorna. cioè l'evento NON è stato annullato restituendo false.

Se cerchiamo le specifiche (vedi risorse in fondo), vediamo che la nostra funzione callback / handler per addEventListener non supporta un tipo restituito. Possiamo restituire quello che vogliamo, ma poiché non fa parte dell'API / interfaccia del browser, non ha alcun effetto.

Soluzione: utilizzando event.preventDefault()invece di 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();

strumenti di sviluppo del browser ...

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

dà ...

function eventHandler (ev) {
    // want to prevent link navigation
    ev.preventDefault();
    alert('eventHandler ran');
}

...come previsto.

Riprovare:

  • Fare clic sul collegamento.
  • Ricevi l'avviso.
  • Ignora avviso.
  • Non avviene alcuna navigazione o aggiornamento della pagina ... che è ciò che vogliamo.

Quindi con l' addEventListeneruso event.preventDefault()come la restituzione di false non fa nulla.

Risorse

La specifica html5 ( https://www.w3.org/TR/html5/webappapis.html#events ) confonde le cose perché usano entrambi onclicke addEventListenernei loro esempi e dicono quanto segue:

L'algoritmo di elaborazione del gestore eventi per un gestore eventi H e un oggetto Evento E è il seguente:

...

  1. Elabora il valore restituito come segue:

...

Se il valore restituito è un valore falso booleano Web IDL, annullare l'evento.

Quindi sembra implicare che return falseannulli l'evento per entrambi addEventListenere onclick.

Ma, se guardi la loro definizione collegata di event-handlerte, vedi:

Un gestore di eventi ha un nome, che inizia sempre con "on" ed è seguito dal nome dell'evento a cui è destinato.

...

I gestori di eventi vengono esposti in uno dei due modi.

Il primo modo, comune a tutti i gestori di eventi, è come attributo IDL del gestore di eventi.

Il secondo modo è come attributo di contenuto del gestore di eventi. I gestori di eventi sugli elementi HTML e alcuni dei gestori di eventi sugli oggetti Window vengono esposti in questo modo.

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

Quindi sembra che l' return falseannullamento dell'evento si applichi davvero solo ai gestori di eventi onclick(o in generale on*) e non ai gestori di eventi registrati tramite i addEventListenerquali ha un'API diversa.

Poiché l' addEventListenerAPI non è coperta dalle specifiche html5 (solo i on*gestori di eventi) ... sarebbe meno confuso se si attenessero ai on*gestori di eventi di stile nei loro esempi.


-2

Differenza tra preventDefault, stopPropogation, return false

Tabella che mostra la differenza

Azione predefinita: azione lato server quando viene generato un evento di controllo.

Supponiamo di avere il controllo div e al suo interno abbiamo un pulsante. Quindi div è il controllo genitore del pulsante. Abbiamo clic lato client e evento clic lato server del pulsante. Inoltre abbiamo un evento clic lato client del div.

All'evento clic del pulsante sul lato client, possiamo controllare le azioni del controllo padre e del codice lato server utilizzando i seguenti tre modi:

  • return false- Ciò consente solo eventi lato client del controllo. L'evento lato server e l'evento lato client del controllo padre non vengono generati.

  • preventDefault()- Ciò consente eventi di controllo lato client e il relativo controllo padre. Evento lato server, ad es. L'azione predefinita del controllo non viene attivata.

  • stopPropogation()- Ciò consente eventi lato client e lato server del controllo. L'evento lato client del controllo non è consentito.


21
Ti sbagli, return falsenon interrompe la propagazione, quindi il controllo padre È attivato ( demo ). Inoltre, non sono sicuro di cosa intendi con " evento clic lato server ".
Oriol

6
@Beginners, ignora questa risposta.
pilau

4
Che cos'è questa assurdità sugli eventi lato server? -1
Mark Amery

Penso che il lato server stia pensando all'ASP, dove è possibile gestire gli eventi sul server.
Andrew

5
Non c'è "lato server" quando si parla di JavaScript ed eventi.
rawpower

-12

return falseè solo per IE, event.preventDefault()è supportato da chrome, ff ... browser moderni


10
Ma su Firefox return falsefunziona come event.preventDefault()quando il gestore di eventi viene aggiunto utilizzando il vecchio modello
Oriol
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.