【问题标题】:How can I detect if a browser is blocking a popup?如何检测浏览器是否阻止弹出窗口?
【发布时间】:2010-09-05 09:34:29
【问题描述】:

有时,我遇到一个网页尝试弹出一个新窗口(用于用户输入或其他重要内容),但弹出窗口阻止程序阻止了这种情况的发生。

调用窗口可以使用哪些方法来确保新窗口正常启动?

【问题讨论】:

    标签: javascript html popup


    【解决方案1】:

    如果你使用 JavaScript 打开弹窗,你可以使用这样的东西:

    var newWin = window.open(url);             
    
    if(!newWin || newWin.closed || typeof newWin.closed=='undefined') 
    { 
        //POPUP BLOCKED
    }
    

    【讨论】:

    • 这是 chrome 的答案:detect-blocked-popup-in-chrome
    • @ajwaka 您能否澄清一下这个答案是否适用于 chrome,或者是否有其他答案对 chrome 更好?谢谢!
    • @ajwaka 至少今天这段代码似乎可以在 chrome 上运行,因此是这个问题。
    • @Crashalot - 你在问我一些我在 6 年前回答过的问题 - 遗憾的是,我不再记得当时的情况,浏览器在 6 年内取得了长足的进步。
    【解决方案2】:

    更新: 弹出窗口存在于真正的远古时代。最初的想法是在不关闭主窗口的情况下显示另一个内容。到目前为止,还有其他方法可以做到这一点:JavaScript 能够向服务器发送请求,因此很少使用弹出窗口。但有时它们仍然很方便。

    过去,邪恶网站经常滥用弹出窗口。一个糟糕的页面可能会打开大量带有广告的弹出窗口。所以现在大多数浏览器都试图阻止弹出窗口并保护用户。

    如果在用户触发的事件处理程序(如 onclick)之外调用弹出窗口,大多数浏览器都会阻止弹出窗口。

    如果你仔细想想,这有点棘手。如果代码直接在 onclick 处理程序中,那很容易。但是 setTimeout 中打开的弹窗是什么?

    试试这个代码:

     // open after 3 seconds
    setTimeout(() => window.open('http://google.com'), 3000);
    

    弹出窗口在 Chrome 中打开,但在 Firefox 中被阻止。

    …这也适用于 Firefox:

     // open after 1 seconds
    setTimeout(() => window.open('http://google.com'), 1000);
    

    不同之处在于 Firefox 认为 2000 毫秒或更短的超时是可以接受的,但在它之后 – 删除“信任”,假设现在它是“用户操作之外的”。所以第一个被屏蔽了,第二个没有。


    2012 年的原始答案:

    此弹出窗口拦截器检查解决方案已在 FF (v11) 中进行了测试, Safari (v6)、Chrome (v23.0.127.95) & IE (v7 & v9)。更新 displayError 函数来处理您认为合适的错误消息。

    var popupBlockerChecker = {
        check: function(popup_window){
            var scope = this;
            if (popup_window) {
                if(/chrome/.test(navigator.userAgent.toLowerCase())){
                    setTimeout(function () {
                        scope.is_popup_blocked(scope, popup_window);
                    },200);
                }else{
                    popup_window.onload = function () {
                        scope.is_popup_blocked(scope, popup_window);
                    };
                }
            } else {
                scope.displayError();
            }
        },
        is_popup_blocked: function(scope, popup_window){
            if ((popup_window.innerHeight > 0)==false){ 
                scope.displayError();
            }
        },
        displayError: function(){
           alert("Popup Blocker is enabled! Please add this site to your exception list.");
        }
    };
    

    用法:

    var popup = window.open("http://www.google.ca", '_blank');
    popupBlockerChecker.check(popup);
    

    希望这会有所帮助! :)

    【讨论】:

    • 我认为你需要更多的下划线
    • 在 Firefox 中,这会显示空白页面,您甚至看不到开启页面上的弹出窗口阻止程序消息。如何关闭空白页?
    • 请注意,如果弹出的 url 是一个可下载的文件(响应头中有Content-Disposition: attachment;),弹出将立即关闭,因此setTimeout 代码将失败,并且浏览器会报错“弹出窗口拦截器已启用!”。对于 Chrome,我推荐 @DanielB 的解决方案,效果很好。
    • @wonsuc 打开带有Content-Disposition: attachment; 标头的链接时,您无需在弹出窗口中打开它。只需直接链接到您想要下载的资产,浏览器的本机行为将允许您下载而不会将您重定向到当前页面。
    • @KevinB 我不得不说我处于特定情况。我必须下载从 HTML 生成 PDF 文件的多个文件。如果HTML内容很大,有时需要几秒钟,如果我使用window.location,如果第一个文件生成时间过长,第二个请求开始时将被忽略。这就是我必须使用window.open 的原因,因为window.location 从不让我知道响应何时结束。
    【解决方案3】:

    我尝试了上面的一些示例,但无法让它们与 Chrome 一起使用。这种简单的方法似乎适用于 Chrome 39、Firefox 34、Safari 5.1.7 和 IE 11。这是我们 JS 库中代码的 sn-p。

    openPopUp: function(urlToOpen) {
        var popup_window=window.open(urlToOpen,"myWindow","toolbar=no, location=no, directories=no, status=no, menubar=no, scrollbars=yes, resizable=yes, copyhistory=yes, width=400, height=400");            
        try {
            popup_window.focus();   
        } catch (e) {
            alert("Pop-up Blocker is enabled! Please add this site to your exception list.");
        }
    }
    

    【讨论】:

    • @Surendra,你能具体说明“不工作”是什么意思吗?解析时出错?运行时出错?弹出窗口打开,但它被标记为被阻止?弹出窗口被阻止但标记为打开?我看不出 explorer 会失败的任何原因,除非在 NULL 上调用 focus() 是允许的,在这种情况下,在 try 之前对 NULL 进行测试就可以了。
    • IE 总是返回 null,即使弹出成功。
    【解决方案4】:

    无论浏览器公司或版本如何,一个始终都可以工作的“解决方案”是简单地在屏幕上放置一条警告消息,靠近将创建一个弹出窗口的控件,礼貌地警告用户该操作需要弹出窗口并请为该站点启用它们。

    我知道这不是什么花哨的东西,但它再简单不过了,只需要大约 5 分钟的测试,然后你就可以继续做其他噩梦了。

    一旦用户允许您的网站弹出窗口,您最好不要过度使用弹出窗口。您最不想做的就是惹恼您的访客。

    【讨论】:

    • 不幸的是,有时这个问题中的所有其他解决方案都不可接受 - 只有这个。为什么?因为他们都试图显示一个弹出窗口 - 而不仅仅是检测是否启用了弹出窗口。如果我想默默地做呢?
    • 这里要记住的一点是,用户不能总是只为您的站点启用弹出窗口。例如,在旧版本的 Safari 中,用户只能完全启用或禁用弹出窗口阻止程序,没有可用的白名单。
    【解决方案5】:

    我尝试了很多解决方案,但我能想到的唯一一个也适用于 uBlock Origin 的方法是利用超时来检查弹出窗口的关闭状态。

    function popup (url, width, height) {
        const left = (window.screen.width / 2) - (width / 2)
        const top = (window.screen.height / 2) - (height / 2)
        let opener = window.open(url, '', `menubar=no, toolbar=no, status=no, resizable=yes, scrollbars=yes, width=${width},height=${height},top=${top},left=${left}`)
    
        window.setTimeout(() => {
            if (!opener || opener.closed || typeof opener.closed === 'undefined') {
                console.log('Not allowed...') // Do something here.
            }
        }, 1000)
    }
    

    显然这是一个 hack;就像这个问题的所有解决方案一样。

    您需要在 setTimeout 中提供足够的时间来计算初始打开和关闭,因此它永远不会完全准确。这将是一个反复试验的位置。

    将此添加到您的尝试列表中。

    【讨论】:

      【解决方案6】:

      通过使用 onbeforeunload 事件我们可以检查如下

          function popup()
          {
              var chk=false;
              var win1=window.open();
              win1.onbeforeunload=()=>{
                  var win2=window.open();
                  win2.onbeforeunload=()=>{
                      chk=true;
                  };
              win2.close();
              };
              win1.close();
              return chk;
          }
      

      它将在后台打开 2 个黑色窗口

      函数返回布尔值。

      【讨论】:

        【解决方案7】:

        我结合了@Kevin B 和@DanielB 的解决方案。
        这要简单得多。

        var isPopupBlockerActivated = function(popupWindow) {
            if (popupWindow) {
                if (/chrome/.test(navigator.userAgent.toLowerCase())) {
                    try {
                        popupWindow.focus();
                    } catch (e) {
                        return true;
                    }
                } else {
                    popupWindow.onload = function() {
                        return (popupWindow.innerHeight > 0) === false;
                    };
                }
            } else {
                return true;
            }
            return false;
        };
        

        用法:

        var popup = window.open('https://www.google.com', '_blank');
        if (isPopupBlockerActivated(popup)) {
            // Do what you want.
        }
        

        【讨论】:

        • isPopupBlockerActivated 函数永远不会返回 return (popupWindow.innerHeight > 0) === false;。当您的浏览器不是 Chrome 时,您的函数返回 false。因为onload是异步过程。您的函数返回 false,然后执行 onload,但它的结果永远不会返回。
        【解决方案8】:

        如果您也拥有子代码,一种简单的方法是在其 html 中创建一个简单的变量,如下所示:

            <script>
                var magicNumber = 49;
            </script>
        

        然后从父母那里检查它的存在,类似于以下内容:

            // Create the window with login URL.
            let openedWindow = window.open(URL_HERE);
        
            // Check this magic number after some time, if it exists then your window exists
            setTimeout(() => {
                if (openedWindow["magicNumber"] !== 32) {
                    console.error("Window open was blocked");
                }
            }, 1500);
        
        

        我们等待一段时间以确保该网页已加载,并检查其是否存在。 显然,如果窗口在 1500 毫秒后没有加载,那么变量仍然是undefined

        【讨论】:

          猜你喜欢
          • 2015-05-05
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-06-03
          • 2019-05-27
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多