我想用 JavaScript 检查用户是否已经在其浏览器的另一个选项卡中打开了我的网站。
看来我无法做到具有页面可见性 …
我看到的唯一方法是使用基于会话cookie的WebSocket,并检查客户端是否具有多个套接字。但是通过这种方式,我必须从当前选项卡中询问服务器,该用户是否在其当前浏览器选项卡旁边打开了一个选项卡。这有点牵强!
也许与localstorage?
localstorage
使用本地存储,我创建了一个简单的演示,该演示应可以完成您的工作。基本上,它只是维护当前打开的窗口的数量。当窗口关闭时,将触发卸载事件,并将其从总窗口数中删除。
当您初看它时,您可能会认为发生的事情比实际更多。多数是为了将逻辑添加到谁是“主”窗口中,以及在关闭孩子时谁应该接管“主”窗口中的尝试。(因此,setTimeout调用以重新检查是否应将其提升到主窗口) 在抓了一些头之后,我认为实现起来将花费太多时间,并且超出了此问题的范围。 但是,如果您打开两个窗口(“主窗口”和“子窗口”)并关闭了“主窗口”,则该子窗口将升级为主窗口。
在大多数情况下,您应该能够大致了解发生的事情并将其用于自己的实现中。
哦,是的,实际上可以看到它的作用…在多个窗口中打开链接。:)
我已经进行了必要的更改,以使本地存储维护“主”窗口。关闭选项卡后,子窗口便可以升级为主窗口。有两种方法可以通过传递给WindowStateManager的构造函数的参数来控制“主”窗口状态。这个实现比我以前的尝试要好得多。
JavaScript:
// noprotect var statusWindow = document.getElementById('status'); (function (win) { //Private variables var _LOCALSTORAGE_KEY = 'WINDOW_VALIDATION'; var RECHECK_WINDOW_DELAY_MS = 100; var _initialized = false; var _isMainWindow = false; var _unloaded = false; var _windowArray; var _windowId; var _isNewWindowPromotedToMain = false; var _onWindowUpdated; function WindowStateManager(isNewWindowPromotedToMain, onWindowUpdated) { //this.resetWindows(); _onWindowUpdated = onWindowUpdated; _isNewWindowPromotedToMain = isNewWindowPromotedToMain; _windowId = Date.now().toString(); bindUnload(); determineWindowState.call(this); _initialized = true; _onWindowUpdated.call(this); } //Determine the state of the window //If its a main or child window function determineWindowState() { var self = this; var _previousState = _isMainWindow; _windowArray = localStorage.getItem(_LOCALSTORAGE_KEY); if (_windowArray === null || _windowArray === "NaN") { _windowArray = []; } else { _windowArray = JSON.parse(_windowArray); } if (_initialized) { //Determine if this window should be promoted if (_windowArray.length <= 1 || (_isNewWindowPromotedToMain ? _windowArray[_windowArray.length - 1] : _windowArray[0]) === _windowId) { _isMainWindow = true; } else { _isMainWindow = false; } } else { if (_windowArray.length === 0) { _isMainWindow = true; _windowArray[0] = _windowId; localStorage.setItem(_LOCALSTORAGE_KEY, JSON.stringify(_windowArray)); } else { _isMainWindow = false; _windowArray.push(_windowId); localStorage.setItem(_LOCALSTORAGE_KEY, JSON.stringify(_windowArray)); } } //If the window state has been updated invoke callback if (_previousState !== _isMainWindow) { _onWindowUpdated.call(this); } //Perform a recheck of the window on a delay setTimeout(function() { determineWindowState.call(self); }, RECHECK_WINDOW_DELAY_MS); } //Remove the window from the global count function removeWindow() { var __windowArray = JSON.parse(localStorage.getItem(_LOCALSTORAGE_KEY)); for (var i = 0, length = __windowArray.length; i < length; i++) { if (__windowArray[i] === _windowId) { __windowArray.splice(i, 1); break; } } //Update the local storage with the new array localStorage.setItem(_LOCALSTORAGE_KEY, JSON.stringify(__windowArray)); } //Bind unloading events function bindUnload() { win.addEventListener('beforeunload', function () { if (!_unloaded) { removeWindow(); } }); win.addEventListener('unload', function () { if (!_unloaded) { removeWindow(); } }); } WindowStateManager.prototype.isMainWindow = function () { return _isMainWindow; }; WindowStateManager.prototype.resetWindows = function () { localStorage.removeItem(_LOCALSTORAGE_KEY); }; win.WindowStateManager = WindowStateManager; })(window); var WindowStateManager = new WindowStateManager(false, windowUpdated); function windowUpdated() { //"this" is a reference to the WindowStateManager statusWindow.className = (this.isMainWindow() ? 'main' : 'child'); } //Resets the count in case something goes wrong in code //WindowStateManager.resetWindows()
HTML:
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>JS Bin</title> </head> <body> <div id='status'> <span class='mainWindow'>Main Window</span> <span class='childWindow'>Child Window</span> </div> </body> </html>
CSS:
#status { display:table; width:100%; height:500px; border:1px solid black; } span { vertical-align:middle; text-align:center; margin:0 auto; font-size:50px; font-family:arial; color:#ba3fa3; display:none; } #status.main .mainWindow, #status.child .childWindow { display:table-cell; } .mainWindow { background-color:#22d86e; } .childWindow { background-color:#70aeff; }