OnBeforeUnloadダイアログをオーバーライドして自分のダイアログで置き換えるにはどうすればよいですか?


346

ユーザーがページを離れる前に、保存されていない変更について警告する必要があります(かなり一般的な問題)。

window.onbeforeunload=handler

これは機能しますが、デフォルトのダイアログが表示され、自分のテキストをラップする刺激的な標準メッセージが表示されます。標準メッセージを完全に置き換えてテキストを明確にするか、jQueryを使用してダイアログ全体をモーダルダイアログに置き換える必要があります。

これまでのところ私は失敗しており、答えを持っていると思われる人は他にいません。可能ですか?

私のページのJavascript:

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

closeIt()関数:

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

jQueryとjqModalを使用して、(カスタム確認ダイアログを使用して)次のようなことを試しました。

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

これも機能しません-beforeunloadイベントにバインドできないようです。


1
現在のコードの例とそれが生成するものを教えてください。
オーウェン

オーウェンは正しいです。そして、その背後にある理由はセキュリティです。ページがアンロードされないようにすることは、Webフォームなどで役立ちますが、悪意のあるサイトで簡単に悪用されて、ユーザーをだましてページにとどまらせることができます。これが、Webブラウザが標準メッセージを実装し、カスタムテキストを挿入するためのこのメカニズムを備えている理由です。
pluckyglen

詳細については、こちらをご覧ください:stackoverflow.com/questions/140460
ベンマッキンタイア


1
chromeでは使用できません。参照:stackoverflow.com/questions/37782104/…–
Abhijeet

回答:


299

のデフォルトのダイアログを変更することはできないためonbeforeunload、これを使用するのが最善の方法です。

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

これはマイクロソフトからの参照です:

文字列がwindow.eventのreturnValueプロパティに割り当てられると、ダイアログボックスが表示され、現在のページに留まり、割り当てられた文字列を保持するオプションをユーザーに提供します。ダイアログボックスに表示されるデフォルトのステートメント「このページから移動してよろしいですか?...続行するには[OK]を、続行するには[キャンセル]を押してください。」を削除または変更することはできません。

問題は次のようです:

  1. ときにonbeforeunload呼ばれ、それは同様ハンドラの戻り値をとりますwindow.event.returnValue
  2. 次に、戻り値を文字列として解析します(nullでない場合)。
  3. 以来、false文字列として解析され、ダイアログボックスは、適切な通過した、発火するtrue/をfalse

その結果は、割り当てる方法があるように思えませんされfalseためにonbeforeunload、デフォルトの対話からそれを防ぐために。

jQueryに関する追加メモ:

  • jQueryでイベントを設定すると、他のイベントも発生するため、問題が発生する可能がありonbeforeunloadます。アンロードイベントのみを発生させたい場合は、JavaScriptをそのまま使用します。
  • jQueryにはショートカットがないonbeforeunloadため、一般的なbind構文を使用する必要があります。

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

2018年9月4日の編集:onbeforeunloadダイアログのカスタムメッセージはchrome-51以降廃止されました(cf:release note


20
最後に示したJQueryの例は、Firefoxで動作しないことがわかりました。代わりに単純な方法を使用してください:window.onbeforeunload = function(){...}
jb。

21
Firefoxが最近変更され、ダイアログ内のテキストをカスタマイズすることさえできないようになりました:bugzilla.mozilla.org/show_bug.cgi
David Hammond

15
しかし、Facebookはどのようにしてカスタムダイアログボックスを提供するのでしょうか。たとえば、メッセージページに移動し、友達のメッセージに返信してから、[送信]をクリックする前に、別のリンクをクリックしてみてください。カスタムダイアログポップアップが表示されます
Varun

20
@Varun-古いニュースですが、Facebookはすべてのアンカーのクリックイベントにハンドラーを配置している可能性がありますが、ブラウザーでURLを書き換えるか、ウィンドウを閉じると、制御できない標準のメソッドに戻ります。
Tabloo Quijico

1
@Varun私はまた、不可能であるこの回答が回答としてフラグが付けられ、150の賛成票があることにも驚いています...実は、FBのカスタムメッセージはサイト内のリンクを通じてのみ利用できます。あなたが単に離れてナビゲートするのではないなら...
セバスチャン・

28

jQueryを使用してIE8、Chrome、Firefoxでテストした結果、次のようになりました。

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

ここではIEと他のブラウザの動作に違いがあるため、プロンプトが必要ない場合は何も返さないことが重要です。


興味深いのevent.returnValueは、IEで唯一「承認された」方法です。IE は、「このプロパティの値は、Microsoft JScriptのreturnステートメントなどによって関数から返される値よりも優先されます」続けます。.. return(イベントからの)とevent.returnValue..の間の保証された相関関係を確認するとよいでしょう

21

状況によっては、ボックスに対してできることは何もありませんが、リンクをクリックしている人を傍受することができます。私にとって、これはほとんどのシナリオで努力する価値があり、フォールバックとして、私はアンロードイベントを残しました。

標準のjQueryダイアログの代わりにBoxyを使用しました。こちらから入手できます: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.';
    }
};

別のイベントにアタッチして、クリックされたアンカーの種類でさらにフィルタリングできますが、これは私にとっては機能し、私がやりたいことであり、他のユーザーが使用または改善するための例として役立ちます。私はこの解決策を望んでいる人のためにこれを共有すると思いました。

私はコードを切り取ったので、これはそのままでは機能しない可能性があります。


「保存したい変更をいくつか加えました。」私にとってはうまくいきませんでした。メッセージを変数「warning_message」に格納する必要があり、warning_messageを返しました。それからそれだけが私のために働きました!。
スガニャ2015

IE、Chrome、Firefoxでテストしましたか?
Kiquenet

9

1)onunloadではなく、onbeforeunloadを使用してください。

2)重要なことは、returnステートメントの実行を回避することです。これによって、ハンドラーから戻るのを回避するという意味ではありません。大丈夫ですが、関数の最後に到達し、returnステートメントを実行しないことを確認することで、正常に戻ります。これらの条件下では、組み込みの標準ダイアログは発生しません。

3)onbeforeunloadを使用している場合は、サーバーで片付けるためにunbeforeunloadハンドラーでajax呼び出しを実行できますが、これは同期的なものである必要があり、onbeforeunloadハンドラーで応答を待機して処理する必要があります(引き続き尊重します)上記の条件(2))。私はこれを行い、それはうまくいきます。同期ajax呼び出しを行う場合、応答が返されるまですべてが保留されます。サーバーからの応答を気にしないと考えて非同期の処理を行うと、ページのアンロードが続行され、このプロセスによってajax呼び出しが中止されます(実行中のリモートスクリプトを含む)。


ただこれを読んでいる人だけです^ Chromeはunbeforeunloadでの同期AJAX呼び出しを非推奨にしています
morganwebdev

4

return;メッセージの代わりにを配置してみてください。これは私にとってほとんどのブラウザで機能しています。(これは本当にダイアログのプレゼントを防ぐだけです)

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

3
nullを返すとダイアログが開かなくなります
Brett Weber

1
nullを返すとダイアログが開かなくなります。Chromeで試してみましたが、実際はそうではありません。
レイ

2
レイのコメントもIEで確認できます。戻るnullと、「null」というテキストのダイアログが開きます。ただし、return void(0);ダイアログは開きません。
MCattle、2015年

1
beforeunload関数内にreturnステートメントを配置しないと、ダイアログは開きません。
OuuGiii 2018


3

onunload関数は、ユーザーがページを離れることを選択したときにのみ呼び出されるため、ユーザーが押したボタン([ok]または[キャンセル])を検出できます。この関数では、DOMが折りたたまれているため、可能性は限られています。JavaScriptを実行できますが、ajax POSTは何も実行しないため、このメソッドを使用して自動ログアウトすることはできません。しかし、そのための解決策があります。window.open( 'logout.php')はonunload関数で実行されるため、ユーザーは新しいウィンドウを開いてログアウトします。

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

このコードは、ユーザーがページを離れたとき、またはアクティブなウィンドウを閉じたときに呼び出され、ユーザーは「logout.php」によってログアウトしました。ログアウトphpがコードで構成されている場合、新しいウィンドウはすぐに閉じます。

window.close();

beforeunloadおよびunload関数で同期ポストを使用できます。特に、サーバーからデータを戻す必要がある場合。これらのブロック内の非同期コードは、ページがアンロードされるまでに完了しない場合があります。
jemiloii

3

私は同じ問題に直面し、メッセージを含む独自のダイアログボックスを取得しても問題ありませんでしたが、直面した問題は次のとおりです。1)すべてのナビゲーションにメッセージが表示され、クローズクリックに対してのみメッセージが表示されました。2)ユーザーが[キャンセル]を選択した場合の私の独自の確認メッセージで、ブラウザのデフォルトのダイアログボックスが表示されます。

以下は、私がマスターページに書いた、見つけたソリューションコードです。

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

「bind」コマンド「one」の専用バージョンを使用するのはどうでしょうか。イベントハンドラーが初めて実行されると、イベントハンドラーとして自動的に削除されます。

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

これが.on( "beforeunload"であることを確認してください
セルジュミンドラス

2
@SergiuMindrasいいえ、それは.one()-イベントリスナーをアタッチして、イベントが1回だけ発生するのをリッスンします。api.jquery.com/one
Sean

0

Angular 9のアプローチ:

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

ブラウザのサポートとカスタムメッセージの削除:

  • Chromeはバージョン51分でカスタムメッセージのサポートを削除しました
  • Operaはver 38分でカスタムメッセージのサポートを削除しました
  • Firefoxはバージョン44.0でカスタムメッセージのサポートを削除しました
  • Safariはバージョン9.1でカスタムメッセージのサポートを削除しました
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.