【问题标题】:Possible to detect if a user has multiple tabs of your site open?是否可以检测用户是否打开了您网站的多个标签?
【发布时间】:2011-05-01 14:50:16
【问题描述】:

我只是在考虑整个网站注册过程。

用户访问您的网站并注册,然后您告诉他您已向他发送了一封电子邮件,他需要验证他的电子邮件地址。所以他点击 Ctrl+T,弹出一个新标签,点击他的Gmail fav 按钮,没有阅读您冗长的欢迎电子邮件,但点击他看到的第一个链接。 Gmail 在另一个标签页中打开您的网站...

他不需要也不希望为您的网站打开两个标签,他只想查看在他注册之前您不允许他访问的那个该死的页面。

那么我们该怎么办?我看到一个网站(但我忘记了它是什么)做得非常好,它实际上刷新了我打开的第一个标签,而无需我按下任何按钮。

我在想,如果我们可以检测到用户是否已经打开了您网站的标签,我们可以自动关闭新的验证标签,或者告诉他他可以关闭它可以返回他的另一个标签(我们现在已经刷新并让他登录了)。

或者,也许当他收到您烦人的“请检查您的电子邮件”消息时,他直接转到他的电子邮件,用他的电子邮件替换您的网站,他完全知道该电子邮件会将他再次链接回该网站。在这种情况下,我们不想关闭选项卡,但也许可以保存他之前的位置,然后再次将他重定向到那里?

无论如何,这只是用例......问题仍然存在。 我们能否检测用户是否已打开您网站的标签页?


这个问题不是关于如何检测何时用户完成了注册过程。 Ajax polling 或 comet 可以解决这个问题。我特别想知道用户是否已经打开了您网站的标签。

【问题讨论】:

  • 我没有足够的说服力来写出完整的答案 - 但基本上,您需要使用 cookie、本地存储或服务器端来跟踪它 - 实际上,任何形式的外部存储数据单个窗口。
  • @Ed:我在乎。我注意到一些小事。那个网站给我留下了很好的印象!
  • 你的目标浏览器是什么?你能用localStorage之类的东西吗?
  • 让您的页面将 date.getTime() 存储到一个变量中。将 localStorage["whatever"] 设置为存储的值。每隔几秒钟,检查一下 localStorage["whatever"] 是否等于您之前设置的值。如果没有,你肯定有两个或更多的页面实例。
  • 也许这个答案可能会有所帮助:stackoverflow.com/a/62231610/2661938

标签: javascript browser tabs user-experience


【解决方案1】:

可以通过在每个标签的localstorage 中保存数据并计算相同的数据来跟踪您网站打开的标签数量,我创建了一个github repository,它可以跟踪用户打开的您网站的标签数量。

使用它在您的页面中包含 tab-counter.js,它将开始跟踪打开的标签页数。

console.log(tabCount.tabsCount());

【讨论】:

    【解决方案2】:

    为了充实 John 的答案,这是一个使用普通 JS 和 localStorage 并使用当前打开的选项卡计数更新 DOM 的工作解决方案。请注意,此解决方案会检测一个浏览器中给定域的打开选项卡/窗口的数量,但不会跨不同浏览器维护计数。

    它使用存储事件来保持计数在所有打开的选项卡/窗口之间保持同步,而无需刷新页面。

    <!DOCTYPE html>
    <html>
    <head>
    <meta http-equiv="content-type" content="text/html; charset=UTF-8">
    <title></title>
    <meta http-equiv="content-type" content="text/html; charset=UTF-8">
    <meta name="robots" content="noindex, nofollow">
    <meta name="googlebot" content="noindex, nofollow">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <script>
    (function() {
        var stor = window.localStorage;
        window.addEventListener("load", function(e) {
            var openTabs = stor.getItem("openTabs");
            if (openTabs) {
                openTabs++;
                stor.setItem("openTabs", openTabs)
            } else {
                stor.setItem("openTabs", 1)
            }
            render();
        })
        window.addEventListener("unload", function(e) {
            e.preventDefault();
            var openTabs = stor.getItem("openTabs");
            if (openTabs) {
                openTabs--;
                stor.setItem("openTabs", openTabs)
            }
            e.returnValue = '';
        });
        window.addEventListener('storage', function(e) {
            render();
        })
    
        function render() {
            var openTabs = stor.getItem("openTabs");
            var tabnum = document.getElementById("tabnum");
            var dname = document.getElementById("dname");
            tabnum.textContent = openTabs;
            dname.textContent = window.location.host
        }
    }());
    </script>
    </head>
    <body>
    <div style="width:100%;height:100%;text-align:center;">
        <h1 >You Have<h1>
            <h1 id="tabnum">0</h1>
        <h1>Tab(s) of <span id="dname"></span> Open</h1>
    </div>
    </body>
    </html>
    

    【讨论】:

      【解决方案3】:

      要添加到其他答案: 您也可以使用本地存储。有一个像“openedTabs”这样的条目。当您的页面打开时,增加此数字。当用户离开页面时,减少它。

      【讨论】:

        【解决方案4】:

        我在这里的用例对您来说有点不同,但它会检测是否正在另一个选项卡中访问该站点。在这种情况下,我想将使用某些呼叫中心页面的人限制在一个选项卡上。它运行良好,并且是纯粹的客户端。

        // 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);
        }
        

        【讨论】:

        • 你能总结一下你在这里做什么吗?看起来您正在给每个窗口/选项卡一个随机名称并将其保存到 cookie 中。然后你每 10 秒检查一次 cookie,如果不匹配,你会提醒他们吗?当他们回到 1 个选项卡时,它会重置名称以使第一个选项卡处于良好状态吗?
        • 第一个标签没有收到错误信息;只有后续的选项卡可以。谢谢你,@anthony-vipond——这正是我想要的。
        【解决方案5】:

        当用户打开另一个选项卡或另一个窗口甚至另一个浏览器时,您可以停止页面功能

        $(window).blur(function(){
            // code to stop functioning or close the page  
        });
        

        【讨论】:

          【解决方案6】:

          我在这里参加聚会已经相当晚了(一年多),但我不禁注意到您错过了一个非常简单和优雅的解决方案(可能是您看到的那个网站使用的)。

          使用 JavaScript,您可以更改当前打开的窗口的名称:

          window.name = "myWindow";
          

          然后,当您发送确认电子邮件时,只需执行以下操作(假设您发送的是 HTML 电子邮件):

          <a href="verificationlink.php" target="myWindow">Verify</a>
          

          这应该会导致verificationLink 在您的网站已经加载到的窗口中打开,如果它已经关闭,它将打开一个带有指定窗口名称的新选项卡。

          【讨论】:

          • 如果页面在两个不同的浏览器中打开,则无法正常工作。但当然,问题中没有提到这一点,所以我说的是什么? :D
          • 这并不能真正回答以下问题:“我们能否检测用户是否已经打开了您网站的标签?”另一个示例可能是,如果用户在您的网站上打开了两个窗口,您想警告他们。
          【解决方案7】:

          用户仍将在服务器上进行会话。为什么不在注册之前存储用户的位置,当他们确认注册时,从会话中读取位置并重定向回该页面。不需要标签魔术。这肯定不是我对注册过程的期望。

          【讨论】:

          • 那么你仍然有第一个标签。
          • 是的。这就是注册过程中发生的事情。我们已经习惯了。
          • 那么两个选项卡都打开了相同的页面...我们不需要两个具有完全相同的页面。我在问如何关闭其中一个。
          • 他们不会。您将有一个带有注册最后一页的标签,另一个带有您的目的地。当您发现另一个选项卡时,您打算做什么?尝试关闭它?这出乎意料。
          • 然后通知他们他们可以关闭它,因为other选项卡包含他们想要的信息。而且它不会包含“注册的最后一页”,因为我们刚刚重定向了它们,记得吗?我的建议是(a)如果用户打开了两个选项卡,关闭一个,或者通知他可以关闭它,然后刷新另一个,或者(b)如果用户已经关闭了原始选项卡,则重定向新选项卡
          【解决方案8】:

          您可以每隔 X 秒从原始选项卡发送一个 AJAX 请求,询问服务器是否收到来自电子邮件的请求。

          您不能自动关闭第二个选项卡,但您可以让它在 3X 秒后询问服务器是否收到了第一个选项卡。

          【讨论】:

            猜你喜欢
            • 2020-12-09
            • 2010-10-25
            • 2013-06-17
            • 1970-01-01
            • 2010-11-04
            • 2014-09-03
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多