Intercetta evento di uscita dalla pagina


117

Durante la modifica di una pagina all'interno del mio sistema, un utente potrebbe decidere di navigare in un altro sito Web e così facendo potrebbe perdere tutte le modifiche che non ha salvato.

Vorrei intercettare qualsiasi tentativo di passare a un'altra pagina e chiedere all'utente di assicurarsi che ciò accada poiché potrebbe potenzialmente perdere il lavoro corrente.

Gmail lo fa in un modo molto simile. Ad esempio, scrivi una nuova email, inizia a digitare nel corpo del messaggio e inserisci una nuova posizione nella barra degli indirizzi (ad esempio twitter.com o qualcosa del genere). Verrà chiesto di chiedere "Sei sicuro?"

Idee su come replicare questo? Sto prendendo di mira IE8, ma vorrei essere compatibile anche con FF e Chrome.


Risposte:


154

Simile alla risposta di Ghommey, ma supporta anche le vecchie versioni di IE e Firefox.

window.onbeforeunload = function (e) {
  var message = "Your confirmation message goes here.",
  e = e || window.event;
  // For IE and Firefox
  if (e) {
    e.returnValue = message;
  }

  // For Safari
  return message;
};

1
Potresti spiegare la prima riga (var message = ...)? Non so cosa stiano facendo quella virgola e la seconda espressione.
mtmurdock

7
@mtmurdock Questa è solo la sintassi Javascript per dichiarare più variabili. var foo, bar;è lo stesso divar foo; var bar;
T Nguyen

4
@mtmurdock, La seconda istruzione " var e = e || window.event;" significa impostare e uguale al parametro e (se è vero) o window.event se non è vero. Non sarà vero se il parametro e è nullo.
T Nguyen

3
@Blieque addEventListener non è supportato in IE8. Non modificare le risposte delle persone senza nemmeno leggere la domanda.
Eli Gray

2
Non funziona più in Chrome (obsoleto): developers.google.com/web/updates/2016/04/…
Micha Schwab

25

Vedi questo articolo. La funzione che stai cercando è onbeforeunload

codice di esempio:

  <script language="JavaScript">
  window.onbeforeunload = confirmExit;
  function confirmExit()
  {
    return "You have attempted to leave this page.  If you have made any changes to the fields without clicking the Save button, your changes will be lost.  Are you sure you want to exit this page?";
  }
</script>

2
Esiste un modo per identificare che l'utente ha scelto l'opzione "Lascia questa pagina" anziché "Rimani in questa pagina"?
Shilpa Soni

@ShilpaSoni riceverai a breve un successivo evento di scaricamento, developer.mozilla.org/en-US/docs/Web/API/Window/unload_event ma non credo che ci sia un modo sincrono.
scipilot

6

Invece di un fastidioso popup di conferma, sarebbe bello ritardare lasciando solo un po '(questione di millisecondi) per gestire correttamente la pubblicazione dei dati non salvati sul server, che ho gestito per il mio sito utilizzando la scrittura di testo fittizio sulla console in questo modo:

window.onbeforeunload=function(e){
  // only take action (iterate) if my SCHEDULED_REQUEST object contains data        
  for (var key in SCHEDULED_REQUEST){   
    postRequest(SCHEDULED_REQUEST); // post and empty SCHEDULED_REQUEST object
    for (var i=0;i<1000;i++){
      // do something unnoticable but time consuming like writing a lot to console
      console.log('buying some time to finish saving data'); 
    };
    break;
  };
}; // no return string --> user will leave as normal but data is send to server

Modifica: vedi anche Synchronous_AJAX e come farlo con jquery


Mi piace questa alternativa al popup. Grazie per il suggerimento, Remi.
Chris Ballance

2
non ha assolutamente senso -1. javascript non è threaded quello che stai facendo è fare un postRequest e poi mettere in pausa il calcolo del sito senza permettere a nessuno di fare nulla (incluso il tuo postRequest, che nel frattempo era già stato inviato prima della pausa di calcolo).
fmsf

Ed è esattamente per questo che funziona: in effetti la richiesta successiva è stata inviata prima della pausa di calcolo, ma questo piccolo blocco della pagina prima che venga effettivamente lasciata assicura abbastanza tempo al client del browser (non javascript) per finire davvero di inviare questa richiesta correttamente . Ho notato che quando invio solo la richiesta (senza bloccare) e abbandono la pagina subito dopo, la richiesta non viene sempre inviata.
Remi

6
Non lo userei in produzione. console.log non è crossbrowser; ogni postRequest soffre del ritardo dei precedenti (il che significa anche che la pagina rimarrà bloccata per tutta la durata del tuo ciclo * richieste pianificate); le richieste non vengono avviate in parallelo; non è garantito che invii veramente le tue richieste. Se fossi costretto ad affrontare questo problema, andrei con una richiesta ajax sincrona, se c'è una sola richiesta. Con più richieste utilizzerei richieste ajax asincrone e un ciclo che controlla i risultati (successo o errore) dai callback delle richieste.
dal

Non sapevo che console.log non fosse cross-browser e una richiesta Ajax sincrona dovrebbe effettivamente essere la soluzione preferita (per una singola richiesta). Il citato SCHEDULED_REQUESTè un oggetto che accumula qualsiasi informazione non urgente che dovrebbe essere inviata al server, come un buffer di dati, unendo effettivamente più richieste a una (ovviamente l'url di queste richieste è lo stesso). L'utilizzo di una richiesta Ajax sincrona prima dello scaricamento dovrebbe risolvere il problema cross-browser come hai detto. Grazie per il tuo prezioso commento!
Remi

0

Ho utenti che non hanno completato tutti i dati richiesti.

<cfset unloadCheck=0>//a ColdFusion precheck in my page generation to see if unload check is needed
var erMsg="";
$(document).ready(function(){
<cfif q.myData eq "">
    <cfset unloadCheck=1>
    $("#myInput").change(function(){
        verify(); //function elsewhere that checks all fields and populates erMsg with error messages for any fail(s)
        if(erMsg=="") window.onbeforeunload = null; //all OK so let them pass
        else window.onbeforeunload = confirmExit(); //borrowed from Jantimon above;
    });
});
<cfif unloadCheck><!--- if any are outstanding, set the error message and the unload alert --->
    verify();
    window.onbeforeunload = confirmExit;
    function confirmExit() {return "Data is incomplete for this Case:"+erMsg;}
</cfif>
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.