我认为使用localStorage是最好的方法。http://www.gwtproject.org/doc/latest/DevGuideHtml5Storage.html
从链接中了解到localStorage:
对其他窗口/标签页的可用性:在同一浏览器运行相同Web应用程序的每个窗口和标签页之间共享
因此,您可以在打开标签页/窗口时设置一个条目,并在关闭它时更改该条目。在打开另一个标签页/窗口时,首先检查此条目值。
显然,您需要小心:例如,浏览器崩溃可能不会触发“关闭”部分,因此用户将无法打开新标签页,即使没有任何标签页打开(localStorage仍然存在!)。如果您有服务器会话,则可以要求用户重新登录(或再次运行身份验证过程),并重置此值。您还可以尝试使用sessionStorage条目来跟踪此类问题。从链接中了解到sessionStorage:
此外,还有一种称为“跨窗口消息传递”的东西,它允许您在选项卡之间进行通信,但请检查您想要支持的浏览器是否支持它。持久性:只在其源窗口或标签页存在期间存活。
http://ajaxian.com/archives/cross-window-messaging-with-html-5-postmessage
我今天做了类似的事情。希望这可以帮到你。
// helper function to set cookies
function setCookie(cname, cvalue, seconds) {
var d = new Date();
d.setTime(d.getTime() + (seconds * 1000));
var expires = "expires="+ d.toUTCString();
document.cookie = cname + "=" + cvalue + ";" + expires + ";path=/";
}
// helper function to get a cookie
function getCookie(cname) {
var name = cname + "=";
var decodedCookie = decodeURIComponent(document.cookie);
var ca = decodedCookie.split(';');
for(var i = 0; i < ca.length; i++) {
var c = ca[i];
while (c.charAt(0) == ' ') {
c = c.substring(1);
}
if (c.indexOf(name) == 0) {
return c.substring(name.length, c.length);
}
}
return "";
}
// Do not allow multiple call center tabs
if (~window.location.hash.indexOf('#admin/callcenter')) {
$(window).on('beforeunload onbeforeunload', function(){
document.cookie = 'ic_window_id=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;';
});
function validateCallCenterTab() {
var win_id_cookie_duration = 10; // in seconds
if (!window.name) {
window.name = Math.random().toString();
}
if (!getCookie('ic_window_id') || window.name === getCookie('ic_window_id')) {
// This means they are using just one tab. Set/clobber the cookie to prolong the tab's validity.
setCookie('ic_window_id', window.name, win_id_cookie_duration);
} else if (getCookie('ic_window_id') !== window.name) {
// this means another browser tab is open, alert them to close the tabs until there is only one remaining
var message = 'You cannot have this website open in multiple tabs. ' +
'Please close them until there is only one remaining. Thanks!';
$('html').html(message);
clearInterval(callCenterInterval);
throw 'Multiple call center tabs error. Program terminating.';
}
}
callCenterInterval = setInterval(validateCallCenterTab, 3000);
}
本地存储(LocalStorage)不能跨协议使用 - 因此,如果用户在一个标签页中使用http打开您的网站,在另一个标签页中使用https打开,这两个标签页将看到不同的本地存储对象。Cookie没有同样的问题(它们有其他问题,例如每个http请求回到您的网站时会膨胀大小)
下面的示例代码维护了一个映射,其中键是唯一的浏览器标识符,值是指示该标签上次确认其仍然打开的时间戳。该映射存储在一个cookie中。这不是一个完美的方法 - 每个标签页每3秒更新一次自身而不是立即更新,并且存在竞争条件(多个标签页更新相同的cookie),但根据您的需求,这可能会解决问题。
如果您只在特定页面上运行此代码,则(或多或少)知道该页面在同一浏览器中是否打开了多次。或者在您网站的每个页面上运行它,并知道您的网站在多个标签页中打开的情况。
为简洁起见,省略了cookie读取/写入代码(但从https://dev59.com/hWUq5IYBdhLWcg3wV_Ei#24103596中获取),并且使用json对cookie中的数据进行编码以简化操作,但您已经了解了思路。
如果您运行此代码并使用FireBug的cookie选项卡观察cookie,您可以看到随着标签页的打开和关闭,cookie会更新。实际上,当有多个标签页打开时,提示用户的操作留给读者自己完成。var timePeriod = 3000; // 3 seconds
function tabHandler() {
// ensure the current window has an identifier set
if (!window.name.match(/^MySite[0-9]{3}/)) {
window.name = 'MySite' + Math.round(Math.random() * 1000);
}
// read in the state of all the tabs
var tabCookie = readCookie('tabs') || null;
var tabs = JSON.parse(tabCookie) || {};
// update the timestamp for the current tab
var now = (new Date()).getTime();
tabs[window.name] = now;
// remove tab details that haven't had their timestamp updated
var tooOld = timePeriod * 2;
for (var tabKey in tabs) {
if ((now - tabs[tabKey]) > tooOld) {
delete tabs[tabKey];
}
}
// write back the current state of tabs
createCookie('tabs', JSON.stringify(tabs), 1);
setTimeout(tabHandler, timePeriod);
}
setTimeout(tabHandler, timePeriod);