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

IT技术 javascript google-chrome popup
2021-02-08 04:36:59

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

var newWin = window.open(url);

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

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

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

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

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

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

6个回答

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

希望这可以帮助。

丰富,你是一个 javascript 弹出高手。谢谢你。这正是我所需要的。
2021-03-13 04:36:59
我想我找到了一种方法来使这项工作适用于新版本的 Chrome。详情请看我的回答。
2021-03-15 04:36:59
此答案不再正确,请将其更改为@Predrag Stojadinović 的答案
2021-03-19 04:36:59
有任何更新吗?似乎不再工作......特别是在Chrome中
2021-03-28 04:36:59
基本上Chrome中存在一个错误。尽管它隐藏了弹出窗口,但它仍然会执行并且您仍然可以返回窗口对象 - 因此常规检查不起作用。这是对我有用的解决方案: 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
2021-03-29 04:36:59

仅对 InvisibleBacon 的 snipet 进行了一项改进(在 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);
    };
}
如果允许弹出窗口,为什么要关闭窗口?这不是关闭您想要打开的弹出窗口吗?
2021-04-05 04:36:59
使用jQuery,而不是onload,我会做$(myPopup).ready()。在本地运行我的 IE 太快了,并且已经发生了“onload”。
2021-04-09 04:36:59

以下是弹出窗口拦截器检查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);

希望这可以帮助!:)

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

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

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从不火。
2021-04-06 04:36:59

这对我有用:

    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 中也不再起作用
2021-03-15 04:36:59
很好地了解了 chrome 的变化,感谢您在此处对其进行更新。您的答案应标记为正确。
2021-03-24 04:36:59