onBeforeUnloadのプロンプトが表示された後にユーザーが滞在したかどうかを検出する

StackOverflow https://stackoverflow.com/questions/821481

  •  03-07-2019
  •  | 
  •  

質問

作業中のWebアプリでは、onBeforeUnloadをキャプチャして、ユーザーが本当に 終了するかどうかを確認しています。

今、もし彼が留まることに決めたら、私がやりたいことがたくさんあります。 私が理解しようとしているのは、彼が実際に留まることを選んだということです。

もちろん、" x"のSetTimeoutを宣言できます。秒が経過し、それが発生した場合、ユーザーがまだそこにいることを意味します(アンロードされなかったため)。問題は、ユーザーが滞在するかどうかをいつでも決めることができるということです...

ダイアログが表示されている間、SetTimeout呼び出しが起動しないことを最初に期待していたので、短い時間にタイムアウトを設定でき、ユーザーが留まることを選択した場合にのみ起動しました。ただし、ダイアログが表示されている間にタイムアウトが実行するため、動作しません。

私が試みた別のアイデアは、ウィンドウ/ドキュメントでmouseMovesをキャプチャすることです。ダイアログが表示されている間、mouseMovesは実際には起動しません。ただし、私のケースに実際に適用される奇妙な例外が1つあるため、どちらも動作しません。

これを行う他の方法を誰も考えられますか?

ありがとう!


(興味がある場合、mouseMoveのキャプチャが機能しない理由は、ページにIFrameがあり、別のドメインからのサイトが含まれているためです。ページのアンロード時にフォーカスがIFrameは、ダイアログが表示されている間に、マウスがIFrameの内側から外側に移動すると(少なくともFirefoxで)MouseMoveイベントを一度発生させます。これはおそらくバグですが、それでも、ので、このメソッドを使用することはできません)。

役に立ちましたか?

解決

私がやったことは、ドキュメントのクリックイベントにフックすることでした。クリックを受け取った後、ユーザーが留まっていると考えました。

これは良い解決策ではありませんが、ほとんどの場合(DiggBarの場合)、多くの偽陰性があります(人々はとどまり、それを知ることはありません)なぜなら、人々はフレーム化されたサイトだけでなく、私たちのサイトと深く関わっているからです。

本質的に、私のコードはこれを行う...

function OnBeforeUnload() {
    Event.observe(document, "click", UserStayed);
    if (IConsiderTheIFrameMightBeTryingToPopOut) {
        return "The site is trying to escape. Do you want to stay?";
    }
}

function UserStayed() {
Event.stopObserving(document, "click", UserStayed);
    // New we know the user is still with us for sure.
}

他のヒント

過去数日間、この質問をオンラインで調査してきましたが、答えは常に「いいえ」です。 (ユーザーが去るとアプリが動作しなくなるという事実を除いて)ユーザーがとどまったか去ったかを確実に知ることはできません。 「いいえ」が嫌い答えます。次のユーティリティを思いつきました。

var OnBeforeUnload = (function(){
    var
    FDUM = new Function,
    AFFIRM = function(){ return true; };

    var _reg = function(msg,opts){
        opts = opts || {};
        var
            pid = null,
            pre = typeof opts.prefire == 'function' ? opts.prefire : FDUM,
            callback = typeof opts.callback == 'function' ? opts.callback : FDUM,
            condition = typeof opts.condition == 'function' ? opts.condition : AFFIRM;

        window.onbeforeunload = function(){
            return condition() ? (pre(),setTimeout(function(){ pid = setTimeout(callback,20); },1),msg) : void 0; 
        }

        window.onunload = function(){ clearTimeout(pid); };

    }

    var _unreg = function(){ window.onbeforeunload = null;  }

    return {
        register : _reg,
        unregister : _unreg
    };

})();

そのため、

などの呼び出し
OnBeforeUnload.register('Hello!',{ 
    condition:function_that_returns_true_to_fire_event_false_to_ignore,
    prefire:function_to_call_on_page_exit_attempt, 
    callback:function_to_call_if_user_stays
});

conditionは、ハンドラー内で呼び出され、アクティブにする必要があるかどうかを確認します。その場合、ポップアップがユーザーに表示される前にプリファイアが実行され(ビデオを一時停止することができます)、ユーザーが留まる場合にのみコールバックが発生します。

私のロジックは、イベントハンドラーの本体でsetTimeoutを開始することでした。ユーザーがいずれかのボタンを押すまで、setTimeoutは実行されません。実行後、すぐに起動します。この場合のsetTimeoutはコールバックを呼び出しませんが、20msの遅延でコールバックの別のタイムアウトを実行するプロキシ関数を呼び出します。ユーザーがページに留まると、コールバックが実行されます。そうでない場合は、別のハンドラーがonunloadに接続され、コールバックを呼び出すタイムアウトがクリアされ、コールバックが呼び出されないようにします。 Firefox、IE、Chromeでしか確認する機会がありませんでしたが、これまで3つすべてで問題なく機能しました。

これが、私が特許「いいえ」であったのと同じくらいイライラした人々を助けることを願っています。この質問に普遍的に与えられた。このコードは完璧ではないかもしれませんが、正しい軌道に乗っていると思います。

これはこのタイプの質問のトップヒットであり、特定のケース(8年前から)がiFrameにあったためにこのソリューションを使用できなかったことを知っていますが、将来の来訪者はおそらくもっと助けられるでしょう上記の回答よりも下の回答で:

bodyイベントリスナーと一緒にいたかどうかは簡単にわかります。mousemoveとkeydownの組み合わせで十分だと思います。

彼らが去ったかどうかを知るには、サーバー側のものが必要になります。

全体として、次のようになります(サーバーへのajax呼び出しを自分で入力する必要があります):

window.addEventListener("beforeunload", function(event){
    //tell your server they are attempting to leave
    var tryLeaveID = serverLogAttempToLeave();

    //an element with giant letters and warning text, because you can no longer set text on the alert box
    var unsavedWarning = document.getElementById("unsavedChangesWarning");
    unsavedWarning.style.display = "block";

    var onStay = function() {
        //if they stay, tell your server so
        serverRevokeAttemptToLeave(tryLeaveID);
        unsavedWarning.style.display = "none";
        document.body.removeEventListener("mousemove", onStay);
        document.body.removeEventListener("keydown", onStay);
    }

    document.body.addEventListener("mousemove", onStay);
    document.body.addEventListener("keydown", onStay);


    var dialogText =  "undisplayed text";
    event.returnValue = dialogText;
    return dialogText;
});

サーバー側では、見苦しいもの、タイマーを使用する必要があります。退出のスタックを作成し、滞在中に要求された場合、または確認された休暇として1分ほど後にそれらを削除します。ユーザーが去ったかどうかを知ることが数分よりも時間に敏感であるというケースは想像できませんが、もしあれば、それについて考えたいのでコメントしてください。

選択を可能にするポップアップボックスが表示されるStackOverflowのメソッドを使用するだけではない理由:

  

このページから移動してよろしいですか?

     

投稿の作成または編集を開始しました。

     

OKを押して続行するか、キャンセルを押して現在のページにとどまります

その後、どれだけ時間がかかるかは関係ありません。 1つのボタンをクリックすると、退出します。相手をクリックしても、そのまま残ります。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top