Javascript 是否可以检测用户是否打开了站点的多个选项卡?

Javascript 是否可以检测用户是否打开了站点的多个选项卡?,javascript,browser,tabs,user-experience,Javascript,Browser,Tabs,User Experience,我只是在考虑整个网站注册过程 用户进入你的网站,注册,然后你告诉他你给他发了一封电子邮件,他需要验证他的电子邮件地址。因此,他点击Ctrl+T,打开一个新标签,点击他的Gmailfav按钮,不读你冗长的欢迎邮件中的任何一个字,而是点击他看到的第一个链接。Gmail将在另一个选项卡中打开您的站点 他不需要也不想打开你网站的两个标签,他只想在他注册之前查看你不允许他访问的那个该死的页面 那我们该怎么办?我看到一个网站(但我忘了它是什么)做得非常好,它实际上刷新了我打开的第一个选项卡,而我不必按任何键

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

用户进入你的网站,注册,然后你告诉他你给他发了一封电子邮件,他需要验证他的电子邮件地址。因此,他点击Ctrl+T,打开一个新标签,点击他的
Gmail
fav按钮,不读你冗长的欢迎邮件中的任何一个字,而是点击他看到的第一个链接。Gmail将在另一个选项卡中打开您的站点

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

那我们该怎么办?我看到一个网站(但我忘了它是什么)做得非常好,它实际上刷新了我打开的第一个选项卡,而我不必按任何键

我在想,如果我们能检测到用户是否已经打开了你网站的一个选项卡,那就更好了。我们可以自动关闭新的验证选项卡,或者告诉他可以关闭它,然后返回到他的另一个选项卡(我们现在已经刷新并让他登录)

或者,当他收到你烦人的“请检查你的电子邮件”信息时,他直接转到他的电子邮件,用他的电子邮件替换你的站点,他很清楚电子邮件会再次将他链接回站点。在这种情况下,我们不想关闭选项卡,但也许可以从以前保存他的位置,然后再次将他重定向到那里

无论如何,这只是一个用例。。。这个问题仍然存在我们是否可以检测用户是否已经打开了站点的选项卡?



这个问题不是关于如何检测用户何时完成注册过程。Ajax轮询或comet可以解决这个问题。我特别想知道用户是否已经有一个选项卡打开到您的站点。

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


您无法自动关闭第二个选项卡,但可以让它在3秒钟后询问服务器是否听到第一个选项卡的声音。

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

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

使用JavaScript,您可以通过以下方式更改当前打开的窗口的名称:

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



这将导致
verificationLink
在您的网站已加载到的窗口内打开,如果该窗口已关闭,则将打开一个具有指定窗口名称的新选项卡

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

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

我这里有一个与您稍有不同的用例,但它检测站点是否在另一个选项卡中被访问。在本例中,我希望将使用呼叫中心页面的用户限制为仅使用一个选项卡。它工作良好,完全是客户端的

// 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的帮助函数
函数setCookie(cname、cvalue、seconds){
var d=新日期();
d、 设置时间(d.getTime()+(秒*1000));
var expires=“expires=“+d.toutString();
document.cookie=cname+“=”+cvalue+”;“+expires+”;path=/”;
}
//获取cookie的助手函数
函数getCookie(cname){
变量名称=cname+“=”;
var decodedCookie=decodeURIComponent(document.cookie);
var ca=decodedCookie.split(“;”);
对于(变量i=0;i
要添加到其他答案中:
您还可以使用本地存储。有一个类似“openedTabs”的条目。打开页面后,增加此数字。当用户离开页面时,减少它。

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

它使用存储事件在所有o中保持计数同步
// 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);
}
<!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>
console.log(tabCount.tabsCount());