如何处理Angular中的浏览器选项卡关闭事件?只关闭,不刷新

时间:2015-12-07 08:33:49

标签: javascript angularjs cookies

我的目标是在浏览器标签关闭时删除用户Cookie。

有可能吗?我可以处理浏览器选项卡关闭事件而不刷新案例吗?

如果我使用anchors.rightbeforeunload事件,在用户刷新页面时触发了功能,我不想要这个,我想在关闭标签时运行。

我如何在Angular中执行此操作?

6 个答案:

答案 0 :(得分:12)

不幸的是,这不是一个简单的问题需要解决。但这是可以完成的。下面的答案是从许多不同的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.clientYevent.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   秒消失了,断开用户与服务器的连接。如果一个   在此期间收到断开连接请求取消   从列表中删除相应的断开请求,以便   用户不会断开连接。

     

如果您想要区分,这种方法也适用   选项卡/窗口关闭事件和后续链接或提交的表单。你刚才   需要将两个事件处理程序放在包含链接的每个页面上   和表单以及每个链接/表单登录页面。

结束评论(双关语):

由于您希望在窗口关闭时删除Cookie,因此我假设它阻止在将来的会话中使用它们。如果这是一个正确的假设,上述方法将运作良好。您将无效的cookie保留在服务器上(一旦客户端断开连接),当客户端创建一个新会话时,JS将默认发送cookie,此时您知道它来自较旧的会话,删除它并可选择提供一个新的设置在客户端上。

答案 1 :(得分:6)

$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 detect browser close tab/close browser

<强>更新 我正在研究这个问题以及一些建议。除了以上选项之外,处理此类情况的最佳方法是创建没有活动超时的会话,可能需要25-30分钟。将所有需要销毁的cookie转换为超时会话。或者,您可以设置cookie到期,但随后cookie将保留在浏览器中,直到下次登录。不到25-30分钟的会话不活动是不完全可靠的,因为如果客户端不使用浏览器10-15分钟就可以退出。我甚至尝试过基于链接(&lt; a&gt;)或(&lt; submit&gt;)或(keypress)事件的捕获事件。问题是它能很好地处理页面刷新。但它不会消除客户端在删除cookie之前关闭浏览器或浏览器选项卡的问题。这是您在用例中必须考虑的事情,并且由于无法控制而强行权衡。最好将设计依赖于更好的架构而不是后来面对上述问题。

答案 2 :(得分:3)

答案 3 :(得分:1)

我知道问这个问题已经有一段时间了,但我想我也会提供答案。我发现在不丢失cookie的情况下重新加载页面,并在窗口或标签关闭时删除cookie的最佳方法是使用ng-keydown来观看F5 Keypress(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();
    }
};

}]);

答案 4 :(得分:1)

我刚刚实施了一个(相对)简单的解决方案,上面没有提到。

HTML:

<div
  (window:beforeunload)="doBeforeUnload()"
  (window:unload)="doUnload()"
>
  ... your code here ...
</div>

TS:

  doBeforeUnload() {
    if (document.visibilityState === 'hidden') {
      this.tabWasClosed = true;
    }

    return false;
  }

  doUnload() {
    if (this.tabWasClosed) {
      ... perform logout action ...
    }
  }

我发现 beforeunloadunload 事件的逻辑是:

document.visibilityState 的值:

<头>
卸载前 卸载
标签关闭 '隐藏' '隐藏'
标签已刷新 '可见' '隐藏'

因此您可以将可见性状态与 beforeunload 事件一起使用来区分用户是刷新还是关闭了选项卡。我使用了一些额外的 localStorage 元素来检查注销状态,但这对于 5 年后遇到此问题的任何人来说可能都不需要。

MDN 上关于 document.visibilityState 的更多信息:https://developer.mozilla.org/en-US/docs/Web/API/Document/visibilityState

答案 5 :(得分:0)

如果您的目标是在浏览器关闭时删除Cookie,请不要设置过期时间。 浏览器关闭时会删除没有过期的Cookie。

您真的永远不需要知道用户是否关闭了他们的浏览器。我相信有其他方法可以实现你想要做的任何事情。

底线:

如果访问者不在您的页面上,那么用户使用浏览器或计算机进行的操作实际上与您无关。因此,如果没有来自用户的某种选择,例如浏览器扩展/插件,检测浏览器关闭可能永远不会实现。