Come posso sostituire la finestra di dialogo OnBeforeUnload e sostituirla con la mia?


346

Devo avvertire gli utenti delle modifiche non salvate prima che lascino una pagina (un problema abbastanza comune).

window.onbeforeunload=handler

Funziona ma genera una finestra di dialogo predefinita con un messaggio standard irritante che avvolge il mio testo. Devo sostituire completamente il messaggio standard, quindi il mio testo è chiaro, o (ancora meglio) sostituire l'intera finestra di dialogo con una finestra di dialogo modale utilizzando jQuery.

Finora ho fallito e non ho trovato nessun altro che sembra avere una risposta. È anche possibile?

Javascript nella mia pagina:

<script type="text/javascript">   
   window.onbeforeunload=closeIt;
</script>

La funzione closeIt ():

function closeIt()
{
  if (changes == "true" || files == "true")
  {
      return "Here you can append a custom message to the default dialog.";
  }
}

Usando jQuery e jqModal ho provato questo tipo di cose (usando una finestra di conferma personalizzata):

$(window).beforeunload(function() {
        confirm('new message: ' + this.href + ' !', this.href);
        return false;
    });

che inoltre non funziona - non riesco a legarmi all'evento beforeunload.


1
puoi fare un esempio del tuo codice attuale e di ciò che produce?
Owen,

Owen ha ragione. E, la ragione dietro questo è la sicurezza. Impedire lo scaricamento di una pagina è utile nei moduli Web e simili, ma può essere facilmente sfruttato da un sito dannoso per ingannare l'utente a rimanere su una pagina. Ecco perché i browser Web implementano il messaggio standard e dispongono di questo meccanismo per l'inserimento di testo personalizzato.
pluckyglen,

vedi qui per maggiori informazioni: stackoverflow.com/questions/140460
Ben McIntyre


1
impossibile in Chrome, riferimento: stackoverflow.com/questions/37782104/…
Abhijeet

Risposte:


299

Non puoi modificare la finestra di dialogo predefinita per onbeforeunload, quindi la soluzione migliore potrebbe essere quella di lavorare con essa.

window.onbeforeunload = function() {
    return 'You have unsaved changes!';
}

Ecco un riferimento a questo da Microsoft:

Quando una stringa viene assegnata alla proprietà returnValue di window.event, viene visualizzata una finestra di dialogo che offre agli utenti la possibilità di rimanere sulla pagina corrente e conservare la stringa che le è stata assegnata. L'istruzione predefinita che appare nella finestra di dialogo "Sei sicuro di voler uscire da questa pagina? ... Premi OK per continuare o Annulla per rimanere nella pagina corrente", non può essere rimosso o modificato.

Il problema sembra essere:

  1. Quando onbeforeunloadviene chiamato, prenderà il valore restituito dal gestore come window.event.returnValue.
  2. Quindi analizzerà il valore restituito come stringa (a meno che non sia null).
  3. Poiché falseviene analizzato come una stringa, la finestra di dialogo si attiverà, quindi passerà un true/ false.

Il risultato è, non sembra essere un modo di assegnare falseper onbeforeunloadper evitare che il dialogo di default.

Note aggiuntive su jQuery:

  • L'impostazione dell'evento in jQuery può essere problematica, in quanto consente anche ad altri onbeforeunloadeventi. Se desideri solo che si verifichi il tuo evento di scaricamento, mi atterrerei semplicemente al vecchio JavaScript.
  • jQuery non ha una scorciatoia per onbeforeunloadcui dovresti usare la bindsintassi generica .

    $(window).bind('beforeunload', function() {} );

Modifica 09/04/2018 : i messaggi personalizzati nelle finestre di dialogo onbeforeunload sono obsoleti a partire da chrome-51 (vedi nota di rilascio )


20
Ho scoperto che l'esempio JQuery di dato alla fine non funziona in Firefox. Attenersi invece al modo semplice: window.onbeforeunload = function () {...}
jb.

21
Solo una nota che Firefox è stato recentemente modificato in modo che il testo nella finestra di dialogo non possa nemmeno essere personalizzato: bugzilla.mozilla.org/show_bug.cgi?id=588292
David Hammond

15
Ma come fa Facebook a fornire una finestra di dialogo personalizzata? ad esempio, vai alla pagina dei messaggi, rispondi al messaggio del tuo amico e poi prima di fare clic su Invia, prova a fare clic su un altro link. vedrai una finestra di dialogo personalizzata
Varun

20
@Varun - vecchie notizie, ma Facebook sta probabilmente mettendo i gestori sull'evento click di tutte le loro ancore, ma se riscrivi l'URL nel browser o chiudi la finestra, si ritorna al metodo standard su cui non hanno alcun controllo.
Tabloo Quijico,

1
@Varun Sono anche sorpreso che questa risposta che è impossibile sia contrassegnata come la risposta e abbia 150 voti ... Appena realizzato, il messaggio personalizzato di FB è disponibile solo attraverso i collegamenti all'interno del loro sito. Non se ti allontani semplicemente ...
Sébastien Richer

28

Ciò che ha funzionato per me, usando jQuery e testato in IE8, Chrome e Firefox, è:

$(window).bind("beforeunload",function(event) {
    if(hasChanged) return "You have unsaved changes";
});

È importante non restituire nulla se non è richiesto alcun prompt in quanto vi sono differenze tra IE e altri comportamenti del browser qui.


Interessante, event.returnValueè l'unico metodo "approvato" in IE. IE continua dicendo "Il valore di questa proprietà ha la precedenza sui valori restituiti dalla funzione, ad esempio tramite un'istruzione return di Microsoft JScript." .. sarebbe bello vedere una correlazione garantita tra return(dall'evento) e event.returnValue..

21

Sebbene in alcune circostanze non ci sia nulla che tu possa fare sulla scatola, puoi intercettare qualcuno facendo clic su un link. Per me, questo è valsa la pena per la maggior parte degli scenari e come fallback, ho lasciato l'evento di scarico.

Ho usato Boxy invece della normale finestra di dialogo jQuery, è disponibile qui: http://onehackoranother.com/projects/jquery/boxy/

$(':input').change(function() {
    if(!is_dirty){
        // When the user changes a field on this page, set our is_dirty flag.
        is_dirty = true;
    }
});

$('a').mousedown(function(e) {
    if(is_dirty) {
        // if the user navigates away from this page via an anchor link, 
        //    popup a new boxy confirmation.
        answer = Boxy.confirm("You have made some changes which you might want to save.");
    }
});

window.onbeforeunload = function() {
if((is_dirty)&&(!answer)){
            // call this if the box wasn't shown.
    return 'You have made some changes which you might want to save.';
    }
};

Puoi associarti a un altro evento e filtrare di più su quale tipo di ancoraggio è stato fatto clic, ma questo funziona per me e cosa voglio fare e serve da esempio per gli altri da utilizzare o migliorare. Ho pensato di condividere questo per coloro che desiderano questa soluzione.

Ho tagliato il codice, quindi potrebbe non funzionare così com'è.


return "Hai apportato alcune modifiche che potresti voler salvare." Non ha funzionato per me. Ho dovuto memorizzare il messaggio in una variabile dire 'warning_message' e ho restituito warning_message. Quindi ha funzionato solo per me !.
Suganya,

hai testato in IE, Chrome, Firefox?
Kiquenet,

9

1) Utilizzare onbeforeunload, non onunload.

2) L'importante è evitare di eseguire una dichiarazione di ritorno. Con questo non intendo evitare di tornare dal tuo gestore. Restituisci tutto bene, ma lo fai assicurandoti di raggiungere la fine della funzione e NON eseguire un'istruzione return. In queste condizioni non si verifica la finestra di dialogo standard integrata.

3) È possibile, se si utilizza onbeforeunload, eseguire una chiamata ajax nel gestore unbeforeunload per riordinare il server, ma deve essere sincrono e si deve attendere e gestire la risposta nel gestore onbeforeunload (sempre rispettando condizione (2) sopra). Lo faccio e funziona benissimo. Se si effettua una chiamata Ajax sincrona, tutto viene trattenuto fino a quando non viene restituita la risposta. Se lo fai in modo asincrono, pensando che non ti interessi alla risposta dal server, lo scarico della pagina continua e la tua chiamata ajax viene interrotta da questo processo, incluso uno script remoto se è in esecuzione.


Cordiali saluti, chiunque legga questo ^ Chrome sta deprecando le chiamate AJAX sincrone in un download precedente
morganwebdev

4

Prova a inserire un return;messaggio anziché un messaggio. Questo funziona per me con la maggior parte dei browser. (Questo impedisce davvero solo i regali di dialogo)

window.onbeforeunload = function(evt) {            
        //Your Extra Code
        return;
}

3
return null impedirà l'apertura della finestra di dialogo
Brett Weber

1
return null NON impedisce l'apertura della finestra di dialogo. L'ho provato in Chrome e non è il caso.
Ray,

2
Posso confermare il commento di Ray anche su Internet Explorer. Il ritorno nullaprirà una finestra di dialogo con il testo di "null". Tuttavia, return void(0);non si aprirà la finestra di dialogo.
MCattle,

1
Non inserendo alcuna dichiarazione di ritorno all'interno della funzione beforeunload, la finestra di dialogo non si aprirà.
OuuGiii,


3

È possibile rilevare quale pulsante (ok o annulla) è stato premuto dall'utente, poiché la funzione onunload ha chiamato solo quando l'utente ha scelto di lasciare la pagina. Anche in questa funzione le possibilità sono limitate, perché il DOM è in fase di collasso. È possibile eseguire JavaScript, ma il POST ajax non fa nulla, quindi non è possibile utilizzare questo metodo per il logout automatico. Ma c'è una soluzione per questo. Il window.open ('logout.php') eseguito nella funzione onunload, quindi l'utente si disconnetterà con una nuova apertura della finestra.

function onunload = (){
    window.open('logout.php');
}

Questo codice viene chiamato quando l'utente lascia la pagina o chiude la finestra attiva e l'utente si disconnette da "logout.php". La nuova finestra si chiude immediatamente quando il logout php è costituito da codice:

window.close();

È possibile utilizzare un post sincrono nelle funzioni beforeunload e unload. Soprattutto se hai bisogno di dati indietro dal server. Qualsiasi codice asincrono all'interno di tali blocchi potrebbe non essere completato al momento dello scarico della pagina.
jemiloii,

3

Ho affrontato lo stesso problema, stavo bene per avere una propria finestra di dialogo con il mio messaggio, ma il problema che ho riscontrato è stato: 1) Stava dando un messaggio su tutte le navigazioni lo voglio solo per un clic ravvicinato. 2) con il mio messaggio di conferma, se l'utente seleziona Annulla, mostra ancora la finestra di dialogo predefinita del browser.

Di seguito è riportato il codice delle soluzioni che ho trovato, che ho scritto sulla mia pagina Master.

function closeMe(evt) {
    if (typeof evt == 'undefined') {
        evt = window.event; }
    if (evt && evt.clientX >= (window.event.screenX - 150) &&
        evt.clientY >= -150 && evt.clientY <= 0) {
        return "Do you want to log out of your current session?";
    }
}
window.onbeforeunload = closeMe;

1
 <script type="text/javascript">
        window.onbeforeunload = function(evt) {
            var message = 'Are you sure you want to leave?';
            if (typeof evt == 'undefined') {
                evt = window.event;
            }       
            if (evt) {
                evt.returnValue = message;
            }
            return message;
        } 
    </script>

fare riferimento a http://www.codeprojectdownload.com


1

Che ne dici di usare la versione specializzata del comando "bind" "one". Una volta eseguito il gestore eventi per la prima volta, viene automaticamente rimosso come gestore eventi.

$(window).one("beforeunload", BeforeUnload);

abbastanza sicuro che questo sia .on ("beforeunload"
Sergiu Mindras,

2
@SergiuMindras no, è .one()- che collega un listener di eventi per ascoltare l'evento accadere una sola volta: "Associa un gestore a un evento per gli elementi. Il gestore viene eseguito al massimo una volta per elemento per tipo di evento". api.jquery.com/one
Sean Kendle il

0

Approccio angolare 9:

constructor() {
    window.addEventListener('beforeunload', (event: BeforeUnloadEvent) => {
     if (this.generatedBarcodeIndex) {
      event.preventDefault(); // for Firefox
      event.returnValue = ''; // for Chrome
      return '';
     }
     return false;
    });
   }

Supporto dei browser e rimozione del messaggio personalizzato:

  • Chrome ha rimosso il supporto per il messaggio personalizzato in versione 51 min
  • Opera ha rimosso il supporto per il messaggio personalizzato in versione 38 min
  • Firefox ha rimosso il supporto per il messaggio personalizzato nella versione 44.0 min
  • Safari ha rimosso il supporto per il messaggio personalizzato nella versione 9.1 min
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.