检测 Chrome 中被阻止的弹出窗口

检测 Chrome 中被阻止的弹出窗口

问题描述:

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

I am aware of javascript techniques to detect whether a popup is blocked in other browsers (as described in the answer to this question). Here's the basic test:

var newWin = window.open(url);

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

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

But this does not work in Chrome. The "POPUP BLOCKED" section is never reached when the popup is blocked.

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

Of course, the test is working to an extent since Chrome doesn't actually block the popup, but opens it in a tiny minimized window at the lower right corner which lists "blocked" popups.

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

What I would like to do is be able to tell if the popup was blocked by Chrome's popup blocker. I try to avoid browser sniffing in favor of feature detection. Is there a way to do this without browser sniffing?

编辑:我现在已经尝试使用 newWin.outerHeightnewWin.left 和其他类似的属性来实现这一点.当弹出窗口被阻止时,谷歌浏览器会将所有位置和高度值返回为 0.

Edit: I have now tried making use of newWin.outerHeight, newWin.left, and other similar properties to accomplish this. Google Chrome returns all position and height values as 0 when the popup is blocked.

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

Unfortunately, it also returns the same values even if the popup is actually opened for an unknown amount of time. After some magical period (a couple of seconds in my testing), the location and size information is returned as the correct values. In other words, I'm still no closer to figuring this out. Any help would be appreciated.

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

Well the "magical time" you speak of is probably when the popup's DOM has been loaded. Or else it might be when everything (images, outboard CSS, etc.) has been loaded. You could test this easily by adding a very large graphic to the popup (clear your cache first!). If you were using a Javascript Framework like jQuery (or something similar), you could use the ready() event (or something similar) to wait for the DOM to load before checking the window offset. The danger in this is that Safari detection works in a conflicting way: the popup's DOM will never be ready() in Safari because it'll give you a valid handle for the window you're trying to open -- whether it actually opens or not. (in fact, i believe your popup test code above won't work for safari.)

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

I think the best thing you can do is wrap your test in a setTimeout() and give the popup 3-5 seconds to complete loading before running the test. It's not perfect, but it should work at least 95% of the time.

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

Here's the code I use for cross-browser detection, without the Chrome part.

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 秒的加载时间.在子窗口中,需要添加一个测试函数:

What I do is run this test from the parent and wrap it in a setTimeout(), giving the child window 3-5 seconds to load. In the child window, you need to add a test function:

函数测试(){}

弹出窗口拦截器检测器测试test"函数是否作为子窗口的成员存在.

The popup blocker detector tests to see whether the "test" function exists as a member of the child window.

2015 年 6 月 15 日添加:

ADDED JUNE 15 2015:

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

I think the modern way to handle this would be to use window.postMessage() to have the child notify the parent that the window has been loaded. The approach is similar (child tells parent it's loaded), but the means of communication has improved. I was able to do this cross-domain from the child:

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

父级使用以下方法侦听此消息:

The parent listens for this message using:

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

希望这会有所帮助.