web-dev-qa-db-ja.com

Angularでブラウザタブクローズイベントを処理するにはどうすればよいですか?更新のみではなく、クローズのみ

私の目標は、ブラウザーのタブを閉じたときにユーザーのCookieを削除することです。

出来ますか?更新を行わずにブラウザのタブを閉じるイベントを処理できますか?

beforeunloadまたはunloadイベントを使用する場合、ユーザーがページを更新すると機能がトリガーされます。これは望ましくありません。タブを閉じたときに実行するだけです。

これをAngularでどのように行うことができますか?

26
Furkan Başaran

これは、悲劇的なことに、単純な問題解決ではありません。しかし、それはできます。以下の回答は、さまざまなSO回答から集められたものです。

単純な部分:ウィンドウが破壊されていることを知る。 onunloadイベントハンドルを使用して、これを検出できます。

トリッキーな部分:

更新、リンクフォロー、または目的のウィンドウクローズイベントかどうかを検出します。リンクの削除とフォームの送信は簡単です。

var inFormOrLink;
$('a').live('click', function() { inFormOrLink = true; });
$('form').bind('submit', function() { inFormOrLink = true; });

$(window).bind('beforeunload', function(eventObject) {
    var returnValue = undefined;
    if (! inFormOrLink) {
        returnValue = "Do you really want to close?";
    }
    eventObject.returnValue = returnValue;
    return returnValue;
}); 

貧乏人の解決策

event.clientYまたはevent.clientXイベントを発生させるためにクリックされたものを判別します。

function doUnload(){
 if (window.event.clientX < 0 && window.event.clientY < 0){
   alert("Window closed");
 }
 else{
   alert("Window refreshed");
 }
}

Y軸が機能しないため、リロードまたはタブ/ウィンドウを閉じるボタンのクリックがマイナスになり、キーボードショートカットを使用してリロード(F5、Ctrl-Rなど)およびウィンドウを閉じる(Alt-F4など)とプラスになります)。ブラウザによってボタンの配置が異なるため、X軸は役に立ちません。ただし、制限がある場合は、一連のif-elsesを介してイベント座標を実行するのが最善の策かもしれません。これは確かに信頼できないことに注意してください。

関与するソリューション

Julien Kronegg から取得)HTML5のローカルストレージとクライアント/サーバーの使用AJAX通信。注意:このアプローチは、HTML5ローカルストレージをサポートするブラウザーに限定されます。

ページで、ウィンドウにonunloadを次のハンドラーに追加します

function myUnload(event) {
    if (window.localStorage) {
        // flag the page as being unloading
        window.localStorage['myUnloadEventFlag']=new Date().getTime();
    }

    // notify the server that we want to disconnect the user in a few seconds (I used 5 seconds)
    askServerToDisconnectUserInAFewSeconds(); // synchronous AJAX call
}

次に、onloadon本文を次のハンドラーに追加します

function myLoad(event) {
    if (window.localStorage) {
        var t0 = Number(window.localStorage['myUnloadEventFlag']);
        if (isNaN(t0)) t0=0;
        var t1=new Date().getTime();
        var duration=t1-t0;
        if (duration<10*1000) {
            // less than 10 seconds since the previous Unload event => it's a browser reload (so cancel the disconnection request)
            askServerToCancelDisconnectionRequest(); // asynchronous AJAX call
        } else {
            // last unload event was for a tab/window close => do whatever
        }
    }
} 

サーバーで、切断要求をリストに収集し、定期的にリストを検査するタイマースレッドを設定します(20秒ごとに使用しました)。切断要求がタイムアウトしたら(つまり、5秒が過ぎたら)、ユーザーをサーバーから切断します。その間に切断要求のキャンセルが受信されると、対応する切断要求がリストから削除されるため、ユーザーは切断されません。

このアプローチは、タブ/ウィンドウを閉じるイベントと、フォローされたリンクまたは送信されたフォームを区別する場合にも適用できます。リンクとフォームを含むすべてのページとすべてのリンク/フォームランディングページに2つのイベントハンドラーを配置するだけです。

クロージングコメント(意図したしゃれ):

ウィンドウが閉じられたときにCookieを削除したいので、将来のセッションで使用されないようにすることを想定しています。それが正しい仮定であれば、上記のアプローチはうまく機能します。サーバー上に無効化されたCookieを保持します(クライアントが切断されると)、クライアントが新しいセッションを作成すると、JSはデフォルトでCookieを送信します。この時点で、古いセッションからのものであることがわかり、削除し、オプションでクライアントに設定される新しいもの。

13
Varun Vohra
$window.addEventListener("beforeunload", function (e) {
  var confirmationMessage = "\o/";
  console.log("closing the tab so do your small interval actions here like cookie removal etc but you cannot stop customer from closing");
  (e || window.event).returnValue = confirmationMessage; //Gecko + IE
  return confirmationMessage;                            //Webkit, Safari, Chrome
});

これは、誰でもできる方法でできるかどうかについて、かなり議論されています。しかし、技術的に多くのことをここで行うことはできません。時間が短いため、アクションが完了する前に顧客がそれを閉じると問題が発生し、クライアントを完全に容赦してしまうからです。 $ windowを挿入することを忘れないでください。私はそれに依存しないことをお勧めします。

javascriptがブラウザを閉じる/タブを閉じるを検出する

更新:いくつかの推奨事項とともにこの問題を調査していました。上記のオプションとは別に、このような場合に対処できる最善の方法は、アクティビティタイムアウトが25〜30分にならないセッションを作成することです。破棄する必要があるすべてのCookieをタイムアウト付きのセッションに変換します。または、Cookieの有効期限を設定できますが、Cookieは次のログインまでブラウザに残ります。クライアントが10〜15分間ブラウザを使用していない場合はログアウトできるため、25〜30分間の非アクティブなセッションは完全には信頼できません。リンク(<a>)または(<submit>)または(keypress)ベースのイベントからイベントをキャプチャすることも試みました。問題は、ページの更新を適切に処理することです。ただし、Cookieが削除される前にクライアントがブラウザーまたはブラウザータブを閉じるという問題は解決しません。これは、ユースケースで考慮する必要があり、制御できないために強制的にトレードオフする必要があります。後述の問題に直面するよりも、より良いアーキテクチャへの依存の設計を変更する方が良いです。

6
Gary

たぶん、このリンクはあなたを助けるでしょう http://eureka.ykyuen.info/2011/02/22/jquery-javascript-capture-the-browser-or-tab-closed-event/

3
Adrian Stanescu

この質問が出されてからしばらく経ちましたが、自分の答えも投稿したいと思いました。 Cookieを失うことなくページをリロードし、ウィンドウまたはタブを閉じるときにCookieを削除するために見つけた最良の方法は、ng-keydownを使用してF5キープレス(KeyCode 116)を監視することでした。

[〜#〜] html [〜#〜]

<body ng-controller="exitController" ng-keydown="isRefresh($event)">

[〜#〜] controller [〜#〜]

yourApp.controller('exitController', ['$rootScope', '$scope', '$window', '$cookies', function($rootScope, $scope, $window, $cookies) {
//set refresh to false to start out, it will become true only when we hit the refresh page
$scope.refresh = false;

//This is where we'll actually clear our cookies in the event of a window close
$scope.clearCookies = function() {
    $cookies.remove('sessionData');
    $cookies.remove('ss-id');
    $cookies.remove('ss-pid');
};

//When the user types any key, it will be assessed.
$scope.isRefresh = function(e) {
    var keyCode = e.keyCode; //find the key that was just pressed
    if(keyCode === 116) { //if the key that was pressed is F5, then we know it was a refresh
        $scope.refresh = true;
    }
}

//event that handles all refresh requests
window.onbeforeunload = function (e) {
    if (!$scope.refresh) { //as long as the trigger for the refresh wasnt initiated by F5, we remove the cookies
        $scope.clearCookies();
    }
};

}]);

1
GuyThreepwood64

ブラウザを閉じたときにCookieを削除することが目標である場合は、有効期限を設定しないでください。 有効期限のないCookieは、ブラウザーを閉じると削除されます。

ユーザーがブラウザを閉じたかどうかを知る必要はありません。あなたがやりたいことは何でも達成するための代替方法があると確信しています。

ボトムライン:

訪問者がもうあなたのページにいない場合、ユーザーがブラウザやコンピューターで行っていることは、あなたのビジネスではありません。そのため、ブラウザの終了を検出することは、ユーザーから何らかのオプトインがなければ実装されない可能性があります(例:ブラウザー拡張機能/プラグイン)。

0
flcoder