Jak mogę zastąpić okno dialogowe OnBeforeUnload i zastąpić je własnym?

346

Muszę ostrzec użytkowników przed niezapisanymi zmianami, zanim opuszczą stronę (dość powszechny problem).

window.onbeforeunload=handler

To działa, ale wywołuje domyślne okno dialogowe z irytującą standardową wiadomością, która otacza mój własny tekst. Muszę albo całkowicie zastąpić standardowy komunikat, aby mój tekst był wyraźny, albo (jeszcze lepiej) zastąpić całe okno dialogowe modalnym oknem dialogowym za pomocą jQuery.

Jak dotąd zawiodłem i nie znalazłem nikogo, kto wydaje się mieć odpowiedź. Czy to w ogóle możliwe?

JavaScript na mojej stronie:

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

Funkcja closeIt ():

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

Używając jQuery i jqModal Próbowałem tego rodzaju rzeczy (używając niestandardowego okna dialogowego potwierdzenia):

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

co również nie działa - nie mogę się powiązać ze zdarzeniem beforeunload.

ciało
źródło
1
czy możesz podać przykład swojego obecnego kodu i tego, co on tworzy?
Owen,
Owen ma rację. A powodem tego jest bezpieczeństwo. Zapobieganie rozładowaniu strony jest przydatne w formularzach internetowych i tym podobnych, ale może być łatwo wykorzystana przez złośliwą witrynę, aby oszukać użytkownika, aby pozostał na stronie. Właśnie dlatego przeglądarki internetowe implementują standardowy komunikat i mają ten mechanizm wstawiania niestandardowego tekstu.
pluckyglen
zobacz tutaj, aby uzyskać więcej informacji: stackoverflow.com/questions/140460
Ben McIntyre
1
niemożliwe w chrome, odniesienie: stackoverflow.com/questions/37782104/...
Abhijeet

Odpowiedzi:

300

Nie możesz zmodyfikować domyślnego okna dialogowego onbeforeunload, więc najlepszym rozwiązaniem może być praca z nim.

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

Oto odniesienie do tego od Microsoft:

Gdy ciąg zostanie przypisany do właściwości returnValue window.event, pojawi się okno dialogowe, które daje użytkownikom opcję pozostania na bieżącej stronie i zachowania ciągu, który został do niej przypisany. Domyślne oświadczenie pojawiające się w oknie dialogowym „Czy na pewno chcesz opuścić tę stronę? ... Naciśnij OK, aby kontynuować lub Anuluj, aby pozostać na bieżącej stronie.”, Nie można usunąć ani zmienić.

Problemem wydaje się być:

  1. Kiedy onbeforeunloadjest wywoływany, przyjmuje wartość zwracaną przez moduł obsługi jakowindow.event.returnValue .
  2. Następnie przeanalizuje zwracaną wartość jako ciąg znaków (chyba że ma wartość NULL).
  3. Ponieważ falseparsowany jako ciąg znaków, uruchomi się okno dialogowe, które następnie przekaże odpowiednie true/ false.

Wynik jest, nie wydaje się być sposób przypisywania falseaby onbeforeunloadzapobiec jej z domyślnym dialogu.

Dodatkowe uwagi na temat jQuery:

  • Ustawienie zdarzenia w jQuery może być problematyczne, ponieważ pozwala również onbeforeunloadna wystąpienie innych zdarzeń. Jeśli chcesz, aby wystąpiło tylko zdarzenie rozładowania, trzymałbym się za to zwykłego kodu JavaScript.
  • jQuery nie ma skrótu, onbeforeunloadwięc musisz użyć ogólnej bindskładni.

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

Edytuj 09.04.2018 : niestandardowe komunikaty w oknach dialogowych onbeforeunload są przestarzałe od chrome-51 (por. Uwaga do wydania )

piekarnik
źródło
20
Odkryłem, że podany na końcu przykład JQuery nie działa w firefoxie. Zamiast tego trzymaj się prostej metody: window.onbeforeunload = function () {...}
jb.
21
Tylko uwaga, że ​​Firefox został niedawno zmieniony, aby tekst w oknie dialogowym nie mógł być nawet dostosowany: bugzilla.mozilla.org/show_bug.cgi?id=588292
David Hammond
15
Ale w jaki sposób Facebook udostępnia niestandardowe okno dialogowe? na przykład przejdź do strony wiadomości, odpowiedz na wiadomość znajomego, a następnie, zanim klikniesz Wyślij, spróbuj kliknąć inny link. zobaczysz niestandardowe okno dialogowe
Varun
20
@Varun - stare wiadomości, ale Facebook prawdopodobnie umieszcza programy obsługi dla zdarzenia kliknięcia wszystkich swoich kotwic, ale jeśli przepiszesz adres URL w przeglądarce lub zamkniesz okno, nastąpi powrót do standardowej metody, nad którą nie mają kontroli.
Tabloo Quijico,
1
@ Varun Jestem również zaskoczony, że ta odpowiedź, która jest niemożliwa, jest oznaczona jako odpowiedź i ma 150 głosów pozytywnych ... Właśnie zdałem sobie sprawę, że niestandardowa wiadomość FB jest dostępna tylko poprzez linki w jej witrynie. Nie, jeśli po prostu odpłyniesz ...
Sébastien Richer
28

To, co działało dla mnie, używając jQuery i przetestowane w IE8, Chrome i Firefox, to:

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

Ważne jest, aby niczego nie zwracać, jeśli monit nie jest wymagany, ponieważ występują tutaj różnice między IE a innymi zachowaniami przeglądarki.

perkoz
źródło
Ciekawe, event.returnValueto jedyna „zatwierdzona” metoda w IE. IE mówi dalej: „Wartość tej właściwości ma pierwszeństwo przed wartościami zwracanymi przez funkcję, na przykład za pomocą instrukcji return Microsoft JScript”. .. byłoby miło zobaczyć gwarantowaną korelację między return(z zdarzenia) a event.returnValue..
21

Chociaż w niektórych okolicznościach nie można nic zrobić z tym pudełkiem, możesz przechwycić osobę klikającą link. Dla mnie było to warte wysiłku w przypadku większości scenariuszy i jako awarię opuściłem zdarzenie odciążające.

Użyłem Boxy zamiast standardowego okna dialogowego jQuery, jest on dostępny tutaj: 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.';
    }
};

Możesz dołączyć do innego wydarzenia i filtrować więcej na temat tego, jaki rodzaj kotwicy został kliknięty, ale to działa dla mnie i co chcę zrobić i służy jako przykład dla innych do wykorzystania lub ulepszenia. Pomyślałem, że podzielę się tym dla tych, którzy chcą tego rozwiązania.

Mam wycięty kod, więc może nie działać tak jak jest.

Dan Power
źródło
return „Wprowadziłeś zmiany, które możesz chcieć zapisać”. nie działało dla mnie. Musiałem zapisać wiadomość w zmiennej o treści „wiadomość_ ostrzegawcza” i zwróciłem wiadomość ostrzegawczą. Tylko dla mnie to zadziałało!
Suganya
testowałeś w IE, Chrome, Firefox?
Kiquenet,
9

1) Użyj onbeforeunload, a nie onunload.

2) Ważne jest, aby unikać wykonywania instrukcji return. Nie mam przez to na myśli uniknięcia powrotu od twojego przewodnika. Zwracasz wszystko w porządku, ale robisz to, upewniając się, że dotarłeś do końca funkcji i NIE wykonujesz instrukcji return. W tych warunkach wbudowane standardowe okno dialogowe nie występuje.

3) Jeśli korzystasz z opcji onbeforeunload, możesz uruchomić wywołanie ajax w swoim module obsługi unbeforeunload, aby uporządkować serwer, ale musi to być synchroniczny i musisz poczekać i obsłużyć odpowiedź w module obsługi onbeforeunload (nadal szanując warunek (2) powyżej). Robię to i działa dobrze. Jeśli wykonasz synchroniczne wywołanie ajax, wszystko zostanie wstrzymane do momentu powrotu odpowiedzi. Jeśli zrobisz asynchroniczny, myśląc, że nie zależy ci na odpowiedzi z serwera, odciążanie strony będzie kontynuowane, a twoje wywołanie ajax zostanie przerwane przez ten proces - włączając zdalny skrypt, jeśli jest uruchomiony.

użytkownik1164763
źródło
Po prostu FYI każdy, kto to czyta ^ Chrome przestaje synchronizować połączenia AJAX w unbeforeunload
morganwebdev
4

Spróbuj wstawić return;zamiast wiadomości. Działa to w większości przeglądarek. (To tylko naprawdę zapobiega prezentom dialogowym)

window.onbeforeunload = function(evt) {            
        //Your Extra Code
        return;
}
Donald Powell
źródło
3
return null uniemożliwi otwarcie okna dialogowego
Brett Weber
1
return null NIE uniemożliwi otwarcia okna dialogowego. Próbowałem w Chrome i tak nie jest.
Ray
2
Mogę również potwierdzić komentarz Raya w IE. Wracając nullotworzy się okno dialogowe z tekstem „null”. Jednak return void(0);nie otworzy okna dialogowego.
MCattle
1
Nie wstawiając żadnej instrukcji return do funkcji beforeunload, okno dialogowe nie otworzy się.
OuuGiii
3

Możesz wykryć, który przycisk (OK lub Anuluj) został naciśnięty przez użytkownika, ponieważ funkcja onunload wywoływana jest tylko wtedy, gdy użytkownik zdecyduje się opuścić stronę. Mimo to w tej funkcji możliwości są ograniczone, ponieważ DOM jest zawalony. Możesz uruchomić javascript, ale POST ajax nic nie robi, dlatego nie możesz użyć tej metody do automatycznego wylogowania. Ale istnieje na to rozwiązanie. Window.open ('logout.php') wykonane w funkcji onunload, więc użytkownik wyloguje się z nowym otwarciem okna.

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

Ten kod jest wywoływany, gdy użytkownik opuszcza stronę lub zamyka aktywne okno, a użytkownik wylogował się z pliku „logout.php”. Nowe okno zamyka się natychmiast po wylogowaniu php z kodu:

window.close();
Tamas Cseh
źródło
Możesz użyć postu synchronicznego w funkcjach beforeunload i unload. Zwłaszcza jeśli potrzebujesz danych z powrotem z serwera. Kod asynchroniczny w tych blokach może nie zostać ukończony do czasu rozładowania strony.
jemiloii 19.04.16
3

Napotkałem ten sam problem, mogłem uzyskać własne okno dialogowe z moją wiadomością, ale problem, z którym się spotkałem, to: 1) Dał komunikat na wszystkich nawigacjach, które chcę tylko dla kliknięcia. 2) z własnym komunikatem potwierdzającym, jeśli użytkownik wybierze opcję Anuluj, nadal wyświetla domyślne okno dialogowe przeglądarki.

Poniżej znajduje się kod rozwiązania, który znalazłem, który napisałem na mojej stronie wzorcowej.

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;
Imran Rizvi
źródło
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>

odnoszą się z http://www.codeprojectdownload.com

Krishna Patel
źródło
1

Co powiesz na użycie specjalnej wersji polecenia „bind” „one”. Gdy procedura obsługi zdarzeń zostanie wykonana po raz pierwszy, jest automatycznie usuwana jako procedura obsługi zdarzeń.

$(window).one("beforeunload", BeforeUnload);
Ryga
źródło
całkiem pewne, że to .on („beforeunload”
Sergiu Mindras,
2
@SergiuMindras nie, to .one()- dołącza detektor zdarzeń, aby nasłuchiwać zdarzenia tylko raz: „Dołącz moduł obsługi do zdarzenia dla elementów. Moduł obsługi jest wykonywany najwyżej raz dla elementu na typ zdarzenia”. api.jquery.com/one
Sean Kendle
0

Podejście kątowe 9:

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

Obsługa przeglądarek i usuwanie niestandardowego komunikatu:

  • Chrome usunął obsługę niestandardowej wiadomości w wersji 51 min
  • Opera usunęła obsługę niestandardowej wiadomości w wersji 38 min
  • Firefox usunął obsługę niestandardowej wiadomości w wersji 44,0 min
  • Safari usunęło obsługę niestandardowej wiadomości w wersji 9.1 min
Istvan Dembrovszky
źródło