[英]How can I handle browser tab close event in Angular? Only close, not refresh
我的目标是在浏览器选项卡关闭时删除用户 cookie。
可能吗? 我可以在没有刷新案例的情况下处理浏览器选项卡关闭事件吗?
如果我使用beforeunload
或unload
事件,当用户刷新页面时触发函数,我不想要这个,我只想在关闭选项卡时运行。
我怎样才能在 Angular 中做到这一点?
可悲的是,这不是一个要解决的简单问题。 但这是可以完成的。 下面的答案是由许多不同的 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-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,此时您知道它来自较旧的会话,删除它并可选地提供在客户端上设置一个新的。
$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。 我建议不要依赖它。
更新:我正在研究这个问题以及一些建议。 除了上述选项之外,处理此类情况的最佳方法是创建没有活动超时的会话,可能为 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 ...
}
}
我发现beforeunload
和unload
事件的逻辑是:
document.visibilityState
的值:
卸载前 | 卸下 | |
---|---|---|
标签关闭 | '隐' | '隐' |
标签刷新 | '可见的' | '隐' |
因此,您可以使用带有 beforeunload 事件的 visibilityState 来区分用户是刷新还是关闭了选项卡。 我使用了一些额外的localStorage
元素来检查注销状态,但对于 5 年后遇到此问题的任何人来说,这可能都不需要。
有关 MDN 上document.visibilityState
的更多信息: https ://developer.mozilla.org/en-US/docs/Web/API/Document/visibilityState
我知道这个问题被问到已经有一段时间了,但我想我也会贡献我的答案。 我发现在不丢失 cookie 的情况下重新加载页面以及在窗口或选项卡关闭时删除 cookie 的最佳方法是使用 ng-keydown 来观看 F5 Keypress (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();
}
};
}]);
如果您的目标是在浏览器关闭时删除 cookie,请不要设置过期时间。 当浏览器关闭时,没有过期的 cookie 将被删除。
您真的不需要知道用户是否关闭了浏览器。 我相信有其他方法可以完成您想做的任何事情。
底线:
如果访问者不再出现在您的页面上,那么用户使用浏览器或计算机所做的事情与您无关。 因此,如果没有用户的某种选择,例如浏览器扩展/插件,检测浏览器关闭可能永远不会实现。
参考: https ://www.techiediaries.com/angular-leave-browser-beforeunload-event/
通过在您的应用程序组件或您针对选项卡关闭事件的目标组件中为 window:beforeunload 使用 HostListener 的最佳方式
@HostListener('window:beforeunload')
onBeforeUnload() {
return false;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.