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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/34129319/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 15:56:30  来源:igfitidea点击:

How can I handle browser tab close event in Angular? Only close, not refresh

javascriptangularjscookies

提问by Furkan Ba?aran

My goal is remove user cookies when browser tab closed.

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

Is it possible? Can I handle browser tab close event without refresh case?

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

If I use beforeunloador unloadevents, function triggered when user refresh page, I don't want this, I want just run when closed tab.

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

How can I do this in Angular?

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

采纳答案by vvohra87

This is, tragically, not a simple problem to solve. But it can be done. The answer below is amalgamated from many different SO answers.

可悲的是,这不是一个简单的问题。但这是可以完成的。下面的答案是从许多不同的 SO 答案中合并而来的。

Simple Part:Knowning that the window is being destroyed. You can use the onunloadevent handle to detect this.

简单部分:知道窗口正在被破坏。您可以使用onunload事件句柄来检测这一点。

Tricky Part:

棘手的部分:

Detecting if it's a refresh, link follow or the desired window close event. Removing link follows and form submissions is easy enough:

检测它是刷新、链接跟随还是所需的窗口关闭事件。删除链接和表单提交很容易:

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

Poor-man's Solution

穷人的解决方案

Checking event.clientYor event.clientXto determine what was clicked to fire the event.

检查event.clientYevent.clientX确定点击了什么来触发事件。

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

Y-Axis doesn't work cause it's negative for clicks on reload or tab/window close buttons, and positive when keyboard shortcuts are used to reload (e.g. F5, Ctrl-R, ...) and window closing (e.g. Alt-F4). X-Axis is not useful since different browsers have differing button placements. However, if you're limited, then running the event coordinates thru a series of if-elses might be your best bet. Beware that this is certainly not reliable.

Y 轴不起作用,因为它对重新加载或选项卡/窗口关闭按钮的点击是负面的,当使用键盘快捷键重新加载(例如 F5、Ctrl-R,...)和窗口关闭(例如 Alt-F4)时,它是积极的)。X 轴没有用,因为不同的浏览器有不同的按钮位置。但是,如果您有限,那么通过一系列 if-else 运行事件坐标可能是您最好的选择。请注意,这肯定不可靠。

Involved Solution

涉及的解决方案

(Taken from Julien Kronegg) Using HTML5's local storage and client/server AJAX communication. Caveat: This approach is limited to the browsers which support HTML5 local storage.

(摘自Julien Kronegg)使用 HTML5 的本地存储和客户端/服务器 AJAX 通信。警告:此方法仅限于支持 HTML5 本地存储的浏览器。

On your page, add an onunloadto the window to the following handler

在您的页面上,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
}

Then add a onloadonthe body to the following handler

然后将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
        }
    }
} 

On the server, collect the disconnection requests in a list and set a timer thread which inspects the list at regular intervals (I used every 20 seconds). Once a disconnection request timeout (i.e. the 5 seconds are gone), disconnect the user from the server. If a disconnection request cancelation is received in the meantime, the corresponding disconnection request is removed from the list, so that the user will not be disconnected.

This approach is also applicable if you want to differentiate between tab/window close event and followed links or submitted form. You just need to put the two event handlers on every page which contains links and forms and on every link/form landing page.

在服务器上,收集列表中的断开连接请求,并设置一个定时线程,定期检查列表(我每 20 秒使用一次)。一旦断开请求超时(即 5 秒过去),断开用户与服务器的连接。如果同时接收到断线请求取消,则将相应的断线请求从列表中移除,这样用户就不会被断线。

如果您想区分选项卡/窗口关闭事件和跟踪链接或提交的表单,则此方法也适用。您只需要在包含链接和表单的每个页面以及每个链接/表单登录页面上放置两个事件处理程序。

Closing Comments (pun intended):

结束评论(双关语):

Since you want to remove cookies when the window is closed, I'm assuming it's to prevent them from being used in a future session. If that's a correct assumption, the approach described above will work well. You keep the invalidated cookie on the server (once client is disconnected), when the client creates a new session, the JS will send the cookie over by default, at which point you know it's from an older session, delete it and optionally provide a new one to be set on the client.

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

回答by Gary

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

This is quite debated on whether we can do it or not in a fool proof manner. But technically not a lot of things can be done here since the time you have is quite less and if customer closes it before your actions complete you are in trouble, and you are at mercy of the client completely. Dont forget to inject $window. I advice not to depend on it.

关于我们是否可以以万无一失的方式做到这一点,这是颇有争议的。但从技术上讲,这里不能做很多事情,因为你的时间很少,如果客户在你的行动完成之前关闭它,你就有麻烦了,你完全受客户的摆布。不要忘记注入 $window。我建议不要依赖它。

javascript detect browser close tab/close browser

javascript检测浏览器关闭标签/关闭浏览器

Update:I was researching this issue along with some recommendations. And apart from this above option, the best way you can handle such cases is by creating sessions with no activity timeout of may be 25-30 mins. Convert all your cookies that need to be destroyed into sessions with timeout. Alternately, you can set cookie expiry but then the cookie stays in the browser until next login. Less than 25-30 mins of session inactivity is not completely dependable since you can get logged out if the client is not using the browser for 10-15 mins. I even tried the capturing events from link (<a>) or (<submit>) or (keypress) based events. The problem is it handles page refresh well. But it does not remove the problem of client closing the browser or browser tab before your cookies are deleted. It is something you have to consider in your use case and forcefully trade off due to no control on it. Better to change the design on its dependence to a better architecture than to face mentioned problems later.

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

回答by GuyThreepwood64

I know it's been a while since this question was asked, but I thought I'd contribute my answer as well. The best way I found to reload the page without losing cookies, and remove cookies on window or tab close was to use ng-keydown to watch the F5 Keypress (KeyCode 116).

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

HTML

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

}]);

}]);

回答by flcoder

If your goal is to remove cookies when the browser is closed, don't set expiration. Cookies without expiration are removed when the browser closes.

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

You really should never need to know if a user closes their browser or not. I'm confident there are alternative ways to accomplish whatever it is you're wanting to do.

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

The Bottom Line:

底线:

If a visitor is not on your page anymore, it really is none of your business what the user is doing with their browser or their computer. So detecting browser close will likely never be implemented without some kind of opting-in from the user, e.g., browser extensions/plugins.

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