Mencegat acara keluar halaman

117

Saat mengedit halaman dalam sistem saya, pengguna mungkin memutuskan untuk menavigasi ke situs web lain dan dengan melakukannya dapat kehilangan semua hasil edit yang belum mereka simpan.

Saya ingin menghalangi upaya apa pun untuk membuka halaman lain dan meminta pengguna untuk memastikan bahwa mereka menginginkan hal ini terjadi karena mereka berpotensi kehilangan pekerjaan mereka saat ini.

Gmail melakukannya dengan cara yang sangat mirip. Misalnya, buat email baru, mulailah mengetik ke badan pesan dan masukkan lokasi baru di bilah alamat (katakan twitter.com atau sesuatu). Ini akan meminta "Apakah Anda yakin?"

Ide bagaimana mereplikasi ini? Saya menargetkan IE8, tetapi ingin kompatibel dengan FF & Chrome juga.

Chris Ballance
sumber

Jawaban:

154

Mirip dengan jawaban Ghommey, tetapi ini juga mendukung versi lama IE dan 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;
};
Eli Grey
sumber
1
Bisakah Anda menjelaskan baris pertama (var message = ...)? Aku tidak tahu apa yang dilakukan koma dan ekspresi kedua itu.
mtmurdock
7
@mtmurdock Itu hanya sintaks Javascript untuk mendeklarasikan banyak variabel. var foo, bar;adalah sama denganvar foo; var bar;
T Nguyen
4
@mtmurdock, Pernyataan kedua " var e = e || window.event;" berarti set e sama dengan parameter e (jika benar) atau window.event jika tidak benar. Tidak benar jika parameter e adalah null.
T Nguyen
3
@Blieque addEventListener tidak didukung di IE8. Jangan mengedit jawaban orang tanpa membaca pertanyaannya.
Eli Gray
2
Tidak berfungsi lagi di Chrome (tidak digunakan lagi): developers.google.com/web/updates/2016/04/…
Micha Schwab
25

Lihat artikel ini. Fitur yang Anda cari adalah onbeforeunload

Kode sampel:

  <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>
jantimon
sumber
2
Adakah cara untuk mengidentifikasi bahwa pengguna telah memilih opsi "Keluar dari halaman ini" daripada "Tetap di halaman ini"?
Shilpa Soni
@ShilpaSoni Anda akan segera mendapatkan acara pembongkaran berikutnya, developer.mozilla.org/en-US/docs/Web/API/Window/unload_event tetapi menurut saya tidak ada cara sinkron.
scipilot
6

Alih-alih munculan konfirmasi yang mengganggu, alangkah baiknya untuk menunda menyisakan sedikit (dalam hitungan milidetik) untuk mengelola dengan sukses memposting data yang belum disimpan ke server, yang saya kelola untuk situs saya menggunakan menulis teks tiruan ke konsol seperti ini:

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

Edit: Lihat juga Synchronous_AJAX dan bagaimana melakukannya dengan jquery

Remi
sumber
Saya suka alternatif untuk popup ini. Terima kasih atas sarannya, Remi.
Chris Ballance
2
itu tidak masuk akal sama sekali -1. javascript tidak di-thread apa yang Anda lakukan adalah melakukan postRequest dan kemudian menghentikan komputasi situs tanpa mengizinkan siapa pun untuk melakukan apa-apa (termasuk postRequest Anda, sementara itu sudah dikirim sebelum penghitungan jeda).
fmsf
Dan itulah mengapa ini berfungsi: memang permintaan pasca dikirim sebelum penghitungan jeda, tetapi pemblokiran kecil halaman ini sebelum benar-benar dibiarkan memastikan cukup waktu bagi klien browser (bukan javascript) untuk benar-benar menyelesaikan pengiriman permintaan ini dengan benar . Saya perhatikan bahwa ketika saya hanya mengirim permintaan (tanpa pemblokiran) dan meninggalkan halaman segera setelah itu, permintaan tersebut tidak selalu terkirim.
Remi
6
Saya tidak akan menggunakannya dalam produksi. console.log bukan crossbrowser; setiap postRequest mengalami penundaan dari yang sebelumnya (yang juga berarti halaman akan menggantung di sana selama durasi * permintaan terjadwal loop Anda); permintaan tidak dimulai secara paralel; Anda tidak dijamin benar-benar mengirimkan permintaan Anda. Jika saya dipaksa untuk menghadapi masalah ini, saya akan menggunakan permintaan ajax sinkron, jika hanya ada satu permintaan. Dengan beberapa permintaan, saya akan menggunakan permintaan ajax asinkron dan loop yang memeriksa hasil (baik keberhasilan atau kesalahan) dari panggilan balik permintaan.
framp
Saya tidak tahu bahwa console.log bukanlah cross-browser dan permintaan Synchronous Ajax seharusnya menjadi solusi yang lebih disukai (untuk satu permintaan). Yang disebutkan SCHEDULED_REQUESTadalah objek yang mengakumulasikan informasi tidak mendesak yang harus dikirim ke server, seperti buffer data, secara efektif menggabungkan beberapa permintaan ke satu (tentu saja url permintaan ini sama). Menggunakan permintaan Synchronous Ajax sebelum membongkar harus menyelesaikan masalah lintas-browser seperti yang Anda katakan. Terima kasih atas komentar Anda yang berharga!
Remi
0

Saya memiliki pengguna yang belum melengkapi semua data yang diperlukan.

<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>
gordon
sumber