104

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

var newWin = window.open(url);

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

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

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

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

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

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

4

16 回答 16

67

好吧,您所说的“神奇时间”可能是弹出窗口的 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 秒的加载时间。在子窗口中,需要添加一个测试函数:

功能测试() {}

弹出窗口拦截器检测器测试以查看“测试”功能是否作为子窗口的成员存在。

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

希望这可以帮助。

于 2009-07-07T00:12:49.450 回答
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);
    };
}
于 2011-02-25T11:29:52.197 回答
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);

希望这可以帮助!:)

于 2012-11-30T20:35:09.007 回答
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”属性有时会为失败的弹出窗口报告非零值,即使在 onload 之后也是如此。我也遇到过这种行为,但是如果您在零毫秒超时后添加检查,则 screenX 属性似乎总是​​输出一致的值。

让我知道是否有办法让这个脚本更健壮。似乎为我的目的工作。

于 2010-11-08T16:48:38.707 回答
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();
    }

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

于 2012-06-05T23:18:43.733 回答
5

我将复制/粘贴此处提供的答案: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.");
  }
}
于 2015-02-07T05:27:23.847 回答
4

方法怎么样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这种情况更容易控制流程。

于 2018-10-01T06:58:00.780 回答
2

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

于 2009-03-20T23:01:59.627 回答
2

我在 Chrome 中没有打开弹出窗口时遇到了类似的问题。我很沮丧,因为我并没有试图做一些鬼鬼祟祟的事情,比如 onload 弹出窗口,只是在用户点击时打开一个窗口。我很沮丧,因为从 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 方面有智慧的人可以告诉我们其他人为什么它会有所作为,我很想听听,尽管我怀疑这只是试图关闭恶意程序弹出窗口的大门。

于 2010-07-07T03:52:19.210 回答
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 秒应该是相当安全的)。

于 2010-10-21T18:18:28.340 回答
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();
于 2010-11-02T08:33:44.173 回答
2

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

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

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

于 2009-03-21T00:21:01.387 回答
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>

弹出测试看起来像这样:

<!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 中。IE

function ShowConfirmationMessage()
{
if(popUpsBlocked)
 { 
  alert('Popups are blocked, can not display confirmation popup. A mail will be sent with the confirmation.');
 } 
 else
 { 
  displayConfirmationPopup();
 }
 mailConfirmation();
}
于 2010-05-18T11:14:57.880 回答
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();
            } 
        };
    }
}
于 2011-04-13T09:20:21.543 回答
0

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

var newWin = window.open(url);
if(!newWin || newWin.closed || typeof newWin.closed=='undefined' || newWin.location=='about:blank')
{
    //POPUP BLOCKED
}
于 2010-08-02T11:45:15.433 回答