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

IT技术 javascript angularjs cookies
2021-03-14 03:28:01

我的目标是在浏览器选项卡关闭时删除用户 cookie。

是否可以?我可以在没有刷新的情况下处理浏览器选项卡关闭事件吗?

如果我使用beforeunloadunload事件,用户刷新页面时触发的函数,我不想要这个,我只想在关闭选项卡时运行。

我怎样才能在 Angular 中做到这一点?

6个回答

可悲的是,这不是一个简单的问题要解决。但这是可以完成的。下面的答案是从许多不同的 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-else 运行事件坐标可能是您最好的选择。请注意,这肯定是不可靠的。

涉及的解决方案

(摘自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,此时您知道它来自旧会话,将其删除并可选择提供要在客户端上设置新的。

谢谢你的努力我的朋友。这个答案很有帮助。
2021-04-29 03:28:01
Poor-man's solution 如果用户使用键盘快捷键关闭其选项卡,则效果会更差
2021-05-07 03:28:01
您是否有任何想法在 angular2.x 中执行此操作?
2021-05-08 03:28:01
浏览器被任务管理器杀死的场景呢?
2021-05-16 03:28:01
$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 会保留在浏览器中,直到下次登录。少于 25-30 分钟的会话不活动并不完全可靠,因为如果客户端在 10-15 分钟内不使用浏览器,您可能会被注销。我什至尝试从链接 (< a>) 或 (< submit>) 或 (keypress) 基于事件。问题是它可以很好地处理页面刷新。但它并没有消除客户端在您的 cookie 被删除之前关闭浏览器或浏览器选项卡的问题。这是您在用例中必须考虑的事情,并且由于无法控制而强行权衡。与其在稍后面对提到的问题,不如将设计更改为更好的架构。

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

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事件的逻辑是:

valuedocument.visibilityState

卸载前 卸下
标签关闭 '隐' '隐'
选项卡已刷新 '可见的' '隐'

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

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

我知道这个问题已经有一段时间了,但我想我也会贡献我的答案。我发现在不丢失 cookie 的情况下重新加载页面并在窗口或选项卡关闭时删除 cookie 的最佳方法是使用 ng-keydown 观看 F5 按键(KeyCode 116)。

HTML

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

控制器

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();
    }
};

}]);