检测Chrome中阻止的弹出窗口


103

我知道可以检测其他浏览器是否阻止了弹出窗口的javascript技术(如该问题的答案所述)。这是基本测试:

var newWin = window.open(url);

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

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

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

我想做的就是能够确定弹出窗口是否被Chrome的弹出窗口阻止程序阻止了。我尝试避免浏览器对功能检测的嗅探。有没有办法做到这一点而无需浏览器嗅探?

编辑:我现在尝试使用newWin.outerHeightnewWin.left以及其他类似性质的做到这一点。弹出窗口被阻止时,Google Chrome会将所有位置和高度值返回为0。

不幸的是,即使弹出窗口实际上打开了未知的时间,它也会返回相同的值。经过一段神奇的时期(在我的测试中是几秒钟),位置和大小信息将作为正确的值返回。换句话说,我离解决这个问题还差得远。任何帮助,将不胜感激。


Yoav,无论弹出窗口是否被阻止,位置均显示相同。其他人得到的答案不涉及让用户等待3.5秒吗?

InvisibleBacon和Andy的最新解决方案无法在Chrome 10中使用:即使成功显示了测试弹出窗口,也会出现“无法使用Chrome”消息。任何想法?

我认为这是一个新问题,因为其中一些解决方案似乎仅适用于早期版本的Chrome。
布赖恩·菲尔德

1
@George Bailey我同意,但是要明确一点,其中一些确实可以在当前版本的Chrome(19)中使用。与setTimeout方法结合使用,Andrew最初使用externalHeight的初衷(或其他人建议的screenX)对我来说很好用。但是,是的,在我自己进行测试之前,试图弄清所有这些答案确实很令人困惑。
normalmike

Answers:


66

好吧,您所说的“魔术时间”可能是当弹出窗口的DOM已加载时。否则可能是所有内容(图像,舷外CSS等)均已加载时。您可以通过在弹出窗口中添加一个非常大的图形来轻松地进行测试(首先清除缓存!)。如果您使用的是jQuery之类的Javascript框架(或类似的东西),则可以使用ready()事件(或类似的东西)来等待DOM加载,然后再检查窗口偏移。这样做的危险在于Safari检测的工作方式相互矛盾:弹出窗口的DOM在Safari中永远不会ready(),因为它将为您试图打开的窗口提供有效的句柄-无论它实际上是打开的还是打开的不。(实际上,我认为您上面的弹出式测试代码不适用于野生动物园。)

我认为您可以做的最好的事情是将测试包装在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)
}); 

希望这可以帮助。


丰富,您是JavaScript弹出式大师。谢谢。那正是我所需要的。
安德鲁·恩斯利

4
有任何更新吗?似乎不再起作用了…特别是在Chrome中
Chris Wagner'4

我想我找到了一种方法使之适用于新版本的Chrome。有关详细信息,请参见我的答案。
InvisibleBacon

2
基本上,Chrome中存在一个错误。尽管它隐藏了弹出窗口,但它仍会执行,并且您仍会返回窗口对象-因此常规检查不起作用。这是对我有用的解决方案:var popup = window.open(url); 如果(popup){popup.onload = function(){console.log(popup.innerHeight> 0?'open':'blocked'); }}其他{console.log('blocked'); }这里的工作示例:jsbin.com/uticev/3
Remy Sharp,

1
该答案不再正确,请将其更改为@PredragStojadinović的答案
Lucas B

16

仅是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);
    };
}

如果允许弹出窗口,为什么要关闭窗口?那不会关闭您想首先打开的弹出窗口吗?
elemjay19

3
使用jQuery,而不是onload,我将执行$(myPopup).ready()。在本地运行我的IE太快了,“加载”已经发生。
马特·康诺利

12

以下是用于弹出窗口阻止程序检查的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 Shekhar Giri 2012

您的欢迎Suvendu,很高兴您发现它有用!编码愉快!:)
凯文B

1
我对这段代码进行了调整,以在试图打开的URL中传递/周围。这允许_displayError()方法显示警报(我正在使用Toastr),以通知用户存在问题,并提供可点击的链接来规避大多数阻止程序,因为它是直接链接。感谢分享!!
泰勒·福赛斯

@TylerForsythe您是否有有关您的解决方案的更多信息?希望能够提供直接可点击的内容链接。
约书亚舞

1
@JoshuaDance这是我刚刚创建的要点,以演示修改后的代码以及如何调用它。希望能帮助到你! gist.github.com/tylerforsythe/452ceaad62f507d7cb7bd7ddbffe650c
Tyler Forsythe

10

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”属性有时也会报告失败的弹出窗口非零。我也遇到了这种情况,但是如果您在零毫秒超时后添加检查,那么screenX属性似乎总是​​输出一致的值。

让我知道是否存在使此脚本更强大的方法。似乎为我的目的工作。


它不适合我,onload永不解雇。

9

这对我有用:

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

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


1
chrome更改很不错,感谢您在此处进行更新。您的答案应标记为正确。
Lucas B

在Chrome中,outerWidth和externalHeight也不再起作用
罗马,

5

我将仅复制/粘贴此处提供的答案:DanielB的https://stackoverflow.com/a/27725432/892099。适用于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.");
  }
}

3

方法如何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,我只是认为这iftry / catch这种情况下的控制流程更容易。


这适用于检测chrome扩展adblocker。+1
Micheal C Wallas

2

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


我会尝试的,让您知道我的结果。谢谢。
Andrew Ensley

弹出式窗口被“阻止”时,Google Chrome浏览器将左偏移量和上偏移量报告为0。我以为这是我的金票,但没有。实际打开后,它也会立即将偏移量报告为0。打开后将来某个神奇的时刻,正确记录了顶部和左侧的偏移量。
Andrew Ensley

检查我的帖子,以确保在检查之前已设置偏移量。
InvisibleBacon

2

我在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中打开弹出窗口的最好,最干净的方法。您的答案应该放在首位。其余解决方案只是“肮脏”的骇客。
Mandeep Janjua

2

这是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秒应该是相当安全的)。


2

该片段包含以上所有内容-由于某种原因-StackOverflow排除了下面代码块中的第一行和最后一行代码,因此我在上面写了一个博客。有关完整的说明和其余(可下载的)代码,请访问 我的博客,网址为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();

2

哇,这里肯定有很多解决方案。这是我的,它使用从当前接受的答案中获取的解决方案(在最新的Chrome中不起作用,并且需要将其包装在超时中),以及此线程上的相关解决方案(实际上是普通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);
    }
};

1

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

如今,您真的不需要问“是否阻止了我不请自来的弹出窗口?”这个问题,因为答案始终是“是”-所有主流浏览器默认都启用了弹出窗口阻止程序。最好的方法是仅对window.open()做出响应以直接单击,这几乎总是允许的。


2
我知道最佳实践等。但是,我处于需要完成此任务的情况。这就是为什么我问这个问题而不是“应该吗?”的原因。
安德鲁·恩斯利

1

我稍加修改了上述解决方案,并认为它至少适用于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>

popuptest看起来像这样:

<!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();
}

不幸的是,这假定您要弹出的页面是由我们控制的。我需要打开一个我无法控制的外部页面。
罗马

1
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();
            } 
        };
    }
}

0

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

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

即使未阻止弹出窗口,该位置仍将为“大约:空白”。我在Chrome v28.0.1500.72-
罗马
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.