检查我的网站是否在另一个标签中打开

时间:2014-05-16 00:08:40

标签: javascript html5 websocket

如果用户已经在浏览器的另一个标签页中打开了我的网站,我想查看 JavaScript

我似乎无法用pagevisibility ...

来做到这一点

我看到的唯一方法是使用基于会话cookie的WebSocket,并检查客户端是否有多个套接字。但通过这种方式,从当前选项卡,我必须询问我的服务器该用户是否在其当前浏览器选项卡旁边打开了一个选项卡。这有点牵强!

也许使用localstorage

3 个答案:

答案 0 :(得分:46)

使用本地存储我创建了一个简单的演示,可以完成你想要做的事情。基本上,它只是维护当前打开的窗口的计数。当窗口关闭时,卸载事件将触发并将其从总窗口计数中删除。

当你第一次看到它时,你可能会认为还有比现实更多的事情。其中大部分都是尝试将逻辑添加到谁是主要的"窗口,谁应该接管作为"主要"关闭孩子的窗口。 (因此,setTimeout调用重新检查它是否应该被提升到主窗口)经过一些头疼之后,我认为它需要花费太多时间来实现,并且超出了这个问题的范围。但是,如果您打开了两个窗口(Main和Child)并关闭了Main,则子项将被提升为main。

在大多数情况下,您应该能够了解最新情况并将其用于您自己的实施。

在这里看到一切: http://jsbin.com/mipanuro/1/edit

哦是的,要实际看到它的实际效果......在多个窗口中打开链接。 :)

更新

我做了必要的更改,让本地存储保持" main"窗口。当您关闭标签时,子窗口可以升级为主窗口。有两种方法可以控制" main"窗口状态通过传递给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;
}

答案 1 :(得分:15)

包含localStorage和存储侦听器

的较短版本
<script type="text/javascript">
        // Broad cast that your're opening a page.
        localStorage.openpages = Date.now();
        var onLocalStorageEvent = function(e){
            if(e.key == "openpages"){
                // Listen if anybody else opening the same page!
                localStorage.page_available = Date.now();
            }
            if(e.key == "page_available"){
                alert("One more page already open");
            }
        };
        window.addEventListener('storage', onLocalStorageEvent, false);
</script>

<强>更新

  • 也适用于页面崩溃。
  • 刺激Chrome中的页面崩溃:chrome://inducebrowsercrashforrealz

Live demo

答案 2 :(得分:0)

我知道已经晚了,但也许可以帮助某人

此代码段将检测打开了多少个标签页以及有多少个活动标签页(可见),如果没有标签页处于活动状态,它将选择最后打开的标签页作为活动标签页。

此代码也将处理Windows / tab崩溃,并在崩溃时刷新计数。

因为Stakoverflow当前不支持 localStorage ,请测试here

    response = self.perform_request(log, 'GET', 'network', params=query)
  File "/usr/local/lib/python2.7/query_code.py", line 103, in perform_request
    auth_header = 'Basic %s' % str(":".join([USER_NAME, PASSWORD]).encode('Base64').strip('\r\n'))
TypeError: sequence item 1: expected string or Unicode, NoneType found