【问题标题】:Detect blocked popup in Chrome检测 Chrome 中被阻止的弹出窗口
【发布时间】:2010-10-14 16:11:06
【问题描述】:

我知道 javascript 技术可以检测弹出窗口是否在其他浏览器中被阻止(如 the answer to this question 中所述)。这是基本测试:

var newWin = window.open(url);

if(!newWin || newWin.closed || typeof newWin.closed=='undefined')
{
    //POPUP BLOCKED
}

但这在 Chrome 中不起作用。当弹出窗口被阻止时,永远不会到达“POPUP BLOCKED”部分。

当然,测试在一定程度上是有效的,因为 Chrome 实际上并没有阻止弹出窗口,而是在右下角的一个最小化窗口中打开它,其中列出了“被阻止”的弹出窗口。

我想做的是能够判断弹出窗口是否被 Chrome 的弹出窗口阻止程序阻止。我尽量避免浏览器嗅探以支持特征检测。有没有办法在没有浏览器嗅探的情况下做到这一点?

编辑:我现在尝试使用newWin.outerHeightnewWin.left 和其他类似属性来完成此操作。当弹出窗口被阻止时,谷歌浏览器将所有位置和高度值返回为 0。

不幸的是,即使弹出窗口实际打开了未知的时间,它也会返回相同的值。经过一段神奇的时间(在我的测试中几秒钟),位置和大小信息作为正确的值返回。换句话说,我还没有更接近于弄清楚这一点。任何帮助将不胜感激。

【问题讨论】:

  • Yoav,无论弹出窗口是否被阻止,位置显示都相同。其他人的答案不涉及让用户等待 3.5 秒吗?
  • InvisibleBacon 和 Andy 的最新解决方案在 Chrome 10 中不起作用:即使成功显示了测试弹出窗口,也会出现“chrome 失败”消息。有什么想法吗?
  • 我认为应该提出一个新问题,因为其中一些解决方案似乎只适用于早期版本的 Chrome。
  • @George Bailey 我同意,但为了清楚起见,其中一些确实适用于当前版本的 Chrome (19)。 Andrew 最初使用 outerHeight (或 screenX,正如其他人所建议的那样)的想法对我来说效果很好,并结合了 setTimeout 方法。但是,是的,在我进行自己的测试之前,试图理解所有这些答案真的很令人困惑。

标签: javascript google-chrome popup


【解决方案1】:

嗯,您所说的“神奇时间”可能是弹出窗口的 DOM 已加载时。否则可能是所有内容(图像、外部 CSS 等)都已加载时。您可以通过在弹出窗口中添加一个非常大的图形来轻松测试这一点(首先清除缓存!)。如果您使用 jQuery 之类的 Javascript 框架(或类似的东西),您可以使用 ready() 事件(或类似的东西)等待 DOM 加载,然后再检查窗口偏移量。这样做的危险在于 Safari 检测以一种冲突的方式工作:弹出窗口的 DOM 在 Safari 中永远不会是 ready() 因为它会给你一个有效的句柄来处理你试图打开的窗口——无论它是实际打开还是不是。 (事实上​​,我相信您上面的弹出式测试代码不适用于 safari。)

我认为您能做的最好的事情是将您的测试包装在一个 setTimeout() 中,并在运行测试之前给弹出窗口 3-5 秒来完成加载。它并不完美,但它应该至少在 95% 的时间内都能正常工作。

这是我用于跨浏览器检测的代码,没有 Chrome 部分。

function _hasPopupBlocker(poppedWindow) {
    var result = false;

    try {
        if (typeof poppedWindow == 'undefined') {
            // Safari with popup blocker... leaves the popup window handle undefined
            result = true;
        }
        else if (poppedWindow && poppedWindow.closed) {
            // This happens if the user opens and closes the client window...
            // Confusing because the handle is still available, but it's in a "closed" state.
            // We're not saying that the window is not being blocked, we're just saying
            // that the window has been closed before the test could be run.
            result = false;
        }
        else if (poppedWindow && poppedWindow.test) {
            // This is the actual test. The client window should be fine.
            result = false;
        }
        else {
            // Else we'll assume the window is not OK
            result = true;
        }

    } catch (err) {
        //if (console) {
        //    console.warn("Could not access popup window", err);
        //}
    }

    return result;
}

我所做的是从父级运行此测试并将其包装在 setTimeout() 中,给子窗口 3-5 秒的时间来加载。在子窗口中,需要添加一个测试函数:

函数测试() {}

弹出窗口拦截器检测器会测试“test”函数是否作为子窗口的成员存在。

2015 年 6 月 15 日添加:

我认为处理这个问题的现代方法是使用 window.postMessage() 让孩子通知父母窗口已加载。方法类似(孩子告诉父母它已加载),但沟通方式有所改进。我能够从孩子做这个跨域:

$(window).load(function() {
  this.opener.postMessage({'loaded': true}, "*");
  this.close();
});

父母使用以下方式监听此消息:

$(window).on('message', function(event) {     
  alert(event.originalEvent.data.loaded)
}); 

希望这会有所帮助。

【讨论】:

  • Rich,你是 javascript 弹窗大师。谢谢你。这正是我所需要的。
  • 这方面有什么更新吗?似乎不再起作用了……特别是在 Chrome 中
  • 我想我找到了一种方法,可以让它适用于新版本的 Chrome。详情见我的回答。
  • Chrome 基本上有一个 bug。尽管它隐藏了弹出窗口,但它仍然会执行并且您仍然可以取回窗口对象 - 因此常规检查不起作用。这是对我有用的解决方案: var popup = window.open(url); if (popup) { popup.onload = function () { console.log(popup.innerHeight > 0 ? 'open' : 'blocked'); } } else { console.log('blocked');这里的工作示例:jsbin.com/uticev/3
  • 这个答案不再正确,请改成@Predrag Stojadinović 的答案
【解决方案2】:

仅对 InvisibleBacon 的片段进行了一项改进(在 IE9、Safari 5、Chrome 9 和 FF 3.6 中测试):

var myPopup = window.open("popupcheck.htm", "", "directories=no,height=150,width=150,menubar=no,resizable=no,scrollbars=no,status=no,titlebar=no,top=0,location=no");
if (!myPopup)
    alert("failed for most browsers");
else {
    myPopup.onload = function() {
        setTimeout(function() {
            if (myPopup.screenX === 0) {
                alert("failed for chrome");
            } else {
                // close the test window if popups are allowed.
                myPopup.close();  
            }
        }, 0);
    };
}

【讨论】:

  • 如果允许弹出窗口,为什么要关闭窗口?这不会关闭您首先要打开的弹出窗口吗?
  • 使用 jQuery,而不是 onload,我会做 $(myPopup).ready()。在本地运行我的 IE 太快了,已经发生了“onload”。
【解决方案3】:

以下是一个 jQuery 的弹出式拦截器检查解决方案。它已经在 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);

希望这会有所帮助! :)

【讨论】:

  • 这真的很有帮助。感谢分享。
  • 欢迎您的 Suvendu,很高兴您发现它有用!快乐编码! :)
  • 我调整了这段代码以传入/绕过试图打开的 url。这允许 _displayError() 方法显示一个警报(我正在使用 toastr)通知用户存在问题并提供一个可点击的链接,该链接将绕过大多数阻止程序,因为它是一个直接链接。谢谢分享!!
  • @TylerForsythe 你有关于你的解决方案的更多信息吗?希望能够提供直接可点击的内容链接。
  • @JoshuaDance 这是我刚刚创建的一个要点,用于演示我修改后的代码以及我如何调用它。希望能帮助到你! gist.github.com/tylerforsythe/452ceaad62f507d7cb7bd7ddbffe650c
【解决方案4】:

Rich 的回答不再适用于 Chrome。看起来 Chrome 现在实际上在弹出窗口中执行任何 Javascript。我最终检查了 screenX 值为 0 以检查是否有被阻止的弹出窗口。我还认为我找到了一种方法来保证这个属性在检查之前是最终的。这仅适用于您的域上的弹出窗口,但您可以像这样添加 onload 处理程序:

var myPopup = window.open("site-on-my-domain", "screenX=100");
if (!myPopup)
    alert("failed for most browsers");
else {
    myPopup.onload = function() {
        setTimeout(function() {
            if (myPopup.screenX === 0)
                alert("failed for chrome");
        }, 0);
    };
}

正如许多人所报告的那样,“screenX”属性有时会为失败的弹出窗口报告非零值,即使在 onload 之后也是如此。我也遇到过这种行为,但是如果您在零毫秒超时后添加检查,screenX 属性似乎总是​​输出一致的值。

如果有办法让这个脚本更健壮,请告诉我。不过似乎对我的目的有用。

【讨论】:

  • 它不适合我,onload 永远不会触发。
【解决方案5】:

这对我有用:

    cope.PopupTest.params = 'height=1,width=1,left=-100,top=-100,location=no,toolbar=no,menubar=no,scrollbars=no,resizable=no,directories=no,status=no';
    cope.PopupTest.testWindow = window.open("popupTest.htm", "popupTest", cope.PopupTest.params);

    if( !cope.PopupTest.testWindow
        || cope.PopupTest.testWindow.closed
        || (typeof cope.PopupTest.testWindow.closed=='undefined')
        || cope.PopupTest.testWindow.outerHeight == 0
        || cope.PopupTest.testWindow.outerWidth == 0
        ) {
        // pop-ups ARE blocked
        document.location.href = 'popupsBlocked.htm';
    }
    else {
        // pop-ups are NOT blocked
        cope.PopupTest.testWindow.close();
    }

outerHeight 和 outerWidth 用于 chrome,因为上面的 'about:blank' 技巧不再适用于 chrome。

【讨论】:

  • 很好地了解了 chrome 的变化,感谢您在这里更新它。您的答案应该被标记为正确。
  • outerWidth 和 outerHeight 在 Chrome 中也不再起作用
【解决方案6】:

我将复制/粘贴此处提供的答案:https://stackoverflow.com/a/27725432/892099 by DanielB。适用于 chrome 40,非常干净。没有肮脏的黑客或等待。

function popup(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.");
  }
}

【讨论】:

    【解决方案7】:

    Promise 方法怎么样?

    const openPopUp = (...args) => new Promise(s => {
      const win = window.open(...args)
      if (!win || win.closed) return s()
      setTimeout(() => (win.innerHeight > 0 && !win.closed) ? s(win) : s(), 200)
    })
    

    你可以像经典的window.open一样使用它

    const win = await openPopUp('popuptest.htm', 'popuptest')
    if (!win) {
      // popup closed or blocked, handle alternative case
    }
    

    您可以更改代码,使其不符合承诺,而不是返回undefined,我只是认为if 在这种情况下比try / catch 更容易控制。

    【讨论】:

    • 这适用于检测 chrome 扩展广告拦截器。 +1
    【解决方案8】:

    检查窗口相对于父窗口的位置。 Chrome 使窗口几乎在屏幕外显示。

    【讨论】:

    • 我会尝试并告诉你我的结果。谢谢。
    • 当弹出窗口被“阻止”时,Google Chrome 将左侧和顶部偏移报告为 0。我以为这是我的金票,但不是。它也会在实际打开后立即将偏移量报告为 0。在打开后的某个神奇时刻,正确报告顶部和左侧偏移量。
    • 检查我的帖子以确保在检查之前设置偏移量。
    【解决方案9】:

    我遇到了类似的问题,弹出窗口无法在 Chrome 中打开。我很沮丧,因为我并没有试图做一些鬼鬼祟祟的事情,比如加载弹出窗口,只是在用户点击时打开一个窗口。我很沮丧,因为从 firebug 命令行运行包含 window.open() 的函数有效,而实际上单击我的链接却没有!这是我的解决方案:

    错误的方式:从事件监听器运行 window.open()(在我的例子中,dojo.connect 到 DOM 节点的 onclick 事件方法)。

    dojo.connect(myNode, "onclick", function() {
        window.open();
    }
    

    正确方法:给调用window.open()的节点的onclick属性赋值。

    myNode.onclick = function() {
        window.open();
    }
    

    当然,如果需要,我仍然可以为同一个 onclick 事件创建事件侦听器。通过此更改,即使 Chrome 设置为“不允许任何网站显示弹出窗口”,我也可以打开我的窗口。喜悦。

    如果有谁知道 Chrome 的方式可以告诉我们其他人为什么它会有所作为,我很想听听,尽管我怀疑这只是试图关闭恶意程序弹出窗口的大门。

    【讨论】:

    • 感谢分享您的解决方案。有用。这是在 chrome 中打开弹出窗口的最佳和最干净的方式。你的答案应该是最重要的。其余的解决方案只是“肮脏”的黑客攻击。
    【解决方案10】:

    这是目前在 Chrome 中运行的版本。与 Rich 的解决方案稍有不同,尽管我也添加了一个处理时间的包装器。

    function checkPopupBlocked(poppedWindow) {
     setTimeout(function(){doCheckPopupBlocked(poppedWindow);}, 5000);
    }
    
    function doCheckPopupBlocked(poppedWindow) {
    
        var result = false;
    
        try {
            if (typeof poppedWindow == 'undefined') {
                // Safari with popup blocker... leaves the popup window handle undefined
                result = true;
            }
            else if (poppedWindow && poppedWindow.closed) {
                // This happens if the user opens and closes the client window...
                // Confusing because the handle is still available, but it's in a "closed" state.
                // We're not saying that the window is not being blocked, we're just saying
                // that the window has been closed before the test could be run.
                result = false;
            }
            else if (poppedWindow && poppedWindow.outerWidth == 0) {
                // This is usually Chrome's doing. The outerWidth (and most other size/location info)
             // will be left at 0, EVEN THOUGH the contents of the popup will exist (including the
             // test function we check for next). The outerWidth starts as 0, so a sufficient delay
             // after attempting to pop is needed.
                result = true;
            }
            else if (poppedWindow && poppedWindow.test) {
                // This is the actual test. The client window should be fine.
                result = false;
            }
            else {
                // Else we'll assume the window is not OK
                result = true;
            }
    
        } catch (err) {
            //if (console) {
            //    console.warn("Could not access popup window", err);
            //}
        }
    
        if(result)
         alert("The popup was blocked. You must allow popups to use this site.");
    }
    

    要使用它,只需这样做:

    var popup=window.open('location',etc...);
    checkPopupBlocked(popup);
    

    如果弹出窗口被阻止,警报消息将在 5 秒宽限期后显示(您可以调整,但 5 秒应该是相当安全的)。

    【讨论】:

      【解决方案11】:

      这个片段包含了以上所有内容 - 出于某种原因 - StackOverflow 排除了下面代码块中的第一行和最后一行代码,所以我写了一篇关于它的博客。有关完整说明和其余(可下载)代码,请查看 my blog at thecodeabode.blogspot.com

      var PopupWarning = {
      
          init : function()
          {
      
              if(this.popups_are_disabled() == true)
              {
                  this.redirect_to_instruction_page();
              }
          },
      
          redirect_to_instruction_page : function()
          {
              document.location.href = "http://thecodeabode.blogspot.com";
          },
      
          popups_are_disabled : function()
          {
              var popup = window.open("http://localhost/popup_with_chrome_js.html", "popup_tester", "width=1,height=1,left=0,top=0");
      
              if(!popup || popup.closed || typeof popup == 'undefined' || typeof popup.closed=='undefined')
              {
                  return true;
              }
      
              window.focus();
              popup.blur();
      
              //
              // Chrome popup detection requires that the popup validates itself - so we need to give
              // the popup time to load, then call js on the popup itself
              //
              if(navigator && (navigator.userAgent.toLowerCase()).indexOf("chrome") > -1)
              {
                  var on_load_test = function(){PopupWarning.test_chrome_popups(popup);};     
                  var timer = setTimeout(on_load_test, 60);
                  return;
              }
      
      
              popup.close();
              return false;
          },
      
          test_chrome_popups : function(popup)
          {
              if(popup && popup.chrome_popups_permitted && popup.chrome_popups_permitted() == true)
              {
                  popup.close();
                  return true;
              }
      
              //
              // If the popup js fails - popups are blocked
              //
              this.redirect_to_instruction_page();
          }
      };
      
      PopupWarning.init();
      

      【讨论】:

        【解决方案12】:

        哇,这里肯定有很多解决方案。这是我的,它使用来自 current accepted answer 的解决方案(在最新的 Chrome 中不起作用,需要在超时中包装它),以及 this thread 上的相关解决方案(实际上是 vanilla JS,而不是 jQuery )。

        我的使用回调架构,当弹出窗口被阻止时发送true,否则发送false

        window.isPopupBlocked = function(popup_window, cb)
        {
            var CHROME_CHECK_TIME = 2000;       // the only way to detect this in Chrome is to wait a bit and see if the window is present
        
            function _is_popup_blocked(popup)
            {
                return !popup.innerHeight;
            }
        
            if (popup_window) {
                if (popup_window.closed) {
                    // opened OK but was closed before we checked
                    cb(false);
                    return;
                }
                if (/chrome/.test(navigator.userAgent.toLowerCase())) {
                    // wait a bit before testing the popup in chrome
                    setTimeout(function() {
                        cb(_is_popup_blocked(popup_window));
                    }, CHROME_CHECK_TIME);
                } else {
                    // for other browsers, add an onload event and check after that
                    popup_window.onload = function() {
                        cb(_is_popup_blocked(popup_window));
                    };
                }
            } else {
                cb(true);
            }
        };
        

        【讨论】:

          【解决方案13】:

          Jason的回答也是我能想到的唯一方法,但是这样靠位置有点狡猾!

          这些天来,你真的不需要问“我的主动弹出窗口被阻止了吗?”,因为答案总是“是” — 所有主要浏览器都默认打开了弹出窗口阻止程序。最好的方法是只对 window.open() 进行响应以响应直接点击,这几乎总是被允许的。

          【讨论】:

          • 我知道最佳实践等。但我处于需要完成此任务的情况。这就是为什么我问这个问题而不是“我应该吗?”
          【解决方案14】:

          你好

          我稍微修改了上面描述的解决方案,并认为它至少适用于 Chrome。 我的解决方案是在打开主页时检测弹出窗口是否被阻止,而不是在打开弹出窗口时检测,但我相信有些人可以修改它。:-) 这里的缺点是当没有弹出窗口阻止程序时,弹出窗口会显示几秒钟(可能会缩短一点)。

          我把它放在我的“主”窗口部分

          <script type="text/JavaScript" language="JavaScript">
          
           var mine = window.open('popuptest.htm','popuptest','width=1px,height=1px,left=0,top=0,scrollbars=no');
           if(!mine|| mine.closed || typeof mine.closed=='undefined')
            {
              popUpsBlocked = true       
              alert('Popup blocker detected ');
              if(mine)
                mine.close();
           }
           else
           {
              popUpsBlocked = false    
              var cookieCheckTimer = null;
              cookieCheckTimer =  setTimeout('testPopup();', 3500);
           }
          
          
          function testPopup()
          {
            if(mine)
            {
              if(mine.test())
              {
                 popUpsBlocked = false;
              }
              else
              {
                  alert('Popup blocker detected ');
                   popUpsBlocked = true;
               }
              mine.close();
          }
          
          } 
          </script>
          

          弹出测试看起来像这样:

          <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
          <html xmlns="http://www.w3.org/1999/xhtml" >
          <head>
              <title>Popup test</title>
          <script type="text/javascript" language="Javascript">
             function test() {if(window.innerHeight!=0){return true;} else return false;}
          </script>
          </head>
          
          <body>
          </body>
          </html>
          

          当我在 3500 毫秒后调用弹出页面上的测试功能时,Chrome 已正确设置了内部高度。

          我使用变量 popUpsBlocked 来了解弹出窗口是否在其他 javascript 中显示。 即

          function ShowConfirmationMessage()
          {
          if(popUpsBlocked)
           { 
            alert('Popups are blocked, can not display confirmation popup. A mail will be sent with the confirmation.');
           } 
           else
           { 
            displayConfirmationPopup();
           }
           mailConfirmation();
          }
          

          【讨论】:

          • 不幸的是,这假设您尝试弹出的页面由我们控制。我需要打开一个我无法控制的外部页面。
          【解决方案15】:
          function openPopUpWindow(format)
          {   
              var win = window.open('popupShow.html',
                                    'ReportViewer',
                                    'width=920px,height=720px,left=50px,top=20px,location=no,directories=no,status=no,menubar=no,toolbar=no,resizable=1,maximize:yes,scrollbars=0');
          
              if (win == null || typeof(win) == "undefined" || (win == null && win.outerWidth == 0) || (win != null && win.outerHeight == 0) || win.test == "undefined") 
              {
                  alert("The popup was blocked. You must allow popups to use this site.");  
              }
              else if (win)
              {
                  win.onload = function()
                  {          
                      if (win.screenX === 0) {
                          alert("The popup was blocked. You must allow popups to use this site.");
                          win.close();
                      } 
                  };
              }
          }
          

          【讨论】:

            【解决方案16】:

            据我所知(根据我的测试)Chrome 返回一个位置为“about:blank”的窗口对象。 因此,以下内容应该适用于所有浏览器:

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

            【讨论】:

            • 即使对于未被阻止的弹出窗口,该位置仍将是“about:blank”。我在 Chrome v28.0.1500.72 上测试过
            猜你喜欢
            • 1970-01-01
            • 2013-05-08
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2012-06-25
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多