如何在 Angular 中处理浏览器选项卡关闭事件?只关闭不刷新
Posted
技术标签:
【中文标题】如何在 Angular 中处理浏览器选项卡关闭事件?只关闭不刷新【英文标题】:How can I handle browser tab close event in Angular? Only close, not refresh 【发布时间】:2016-03-11 19:18:55 【问题描述】:我的目标是在浏览器选项卡关闭时删除用户 cookie。
有可能吗?我可以在没有刷新案例的情况下处理浏览器标签关闭事件吗?
如果我使用beforeunload
或unload
事件,当用户刷新页面时触发函数,我不想要这个,我只想在关闭选项卡时运行。
如何在 Angular 中做到这一点?
【问题讨论】:
试试这个:angular.element($window).bind("beforeunload", methodToCall) 我在 .run() 中尝试过,但似乎不起作用。 这段代码遇到了什么问题? 您只能检测页面何时被卸载,而不是何时关闭窗口。此外,onbeforeunload 是非标准的,因此并非所有浏览器都支持。 ***.com/questions/1783302/… 表示无论如何关闭浏览器都会清除cookie。只是不要为它们设置过期时间。 【参考方案1】:可悲的是,这不是一个要解决的简单问题。但这是可以完成的。下面的答案是由许多不同的 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,此时您知道它来自较旧的会话,删除它并可选地提供在客户端上设置新的。
【讨论】:
感谢您的努力,我的朋友。这个答案很有帮助。 你有什么想法在 angular2 中这样做吗? 如果用户使用键盘快捷键关闭标签,Poor-man's solution
会更糟糕
浏览器被任务管理器杀死的场景会怎样?【参考方案2】:
$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 分钟不使用浏览器,您可能会退出。我什至尝试从基于链接 (a>) 或 (submit>) 或 (keypress
) 的事件中捕获事件。问题是它可以很好地处理页面刷新。但这并不能消除客户端在您的 cookie 被删除之前关闭浏览器或浏览器选项卡的问题。这是您在用例中必须考虑的事情,并且由于无法对其进行控制而不得不进行权衡。最好将依赖于设计的设计更改为更好的架构,而不是稍后再面对提到的问题。
【讨论】:
【参考方案3】:也许这个链接会帮助你http://eureka.ykyuen.info/2011/02/22/jquery-javascript-capture-the-browser-or-tab-closed-event/
【讨论】:
【参考方案4】:我刚刚实现了一个(相对)简单的解决方案,上面没有提到。
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 | unload | |
---|---|---|
tab closed | 'hidden' | 'hidden' |
tab refreshed | 'visible' | 'hidden' |
因此您可以使用带有 beforeunload 事件的 visibilityState 来区分用户是刷新还是关闭了选项卡。我使用了一些额外的 localStorage
元素来检查注销状态,但对于 5 年后遇到此问题的任何人来说可能都不需要这样做。
更多关于 document.visibilityState
在 MDN 上:https://developer.mozilla.org/en-US/docs/Web/API/Document/visibilityState
【讨论】:
【参考方案5】:我知道这个问题被问到已经有一段时间了,但我想我也会贡献我的答案。我发现在不丢失 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();
;
]);
【讨论】:
【参考方案6】:如果您的目标是在浏览器关闭时删除 cookie,请不要设置过期时间。 浏览器关闭时会删除未过期的 Cookie。
您真的不需要知道用户是否关闭了浏览器。我相信有其他方法可以完成您想做的任何事情。
底线:
如果访问者不再出现在您的页面上,那么用户使用浏览器或计算机执行的操作确实与您无关。因此,如果没有用户的某种选择,例如浏览器扩展/插件,检测浏览器关闭可能永远不会实现。
【讨论】:
以上是关于如何在 Angular 中处理浏览器选项卡关闭事件?只关闭不刷新的主要内容,如果未能解决你的问题,请参考以下文章