如何检测浏览器是否阻止弹出窗口?


130

有时候,我遇到一个试图弹出一个新窗口(用于用户输入或重要信息)的网页,但是弹出窗口阻止程序阻止了这种情况的发生。

调用窗口可以使用哪些方法来确保新窗口正常启动?

Answers:


160

如果您使用JavaScript打开弹出窗口,则可以使用如下所示的内容:

var newWin = window.open(url);             

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

这是chrome的答案:detect-blocked-popup-in-chrome
ajwaka

@ajwaka是否可以请您澄清此答案是否对chrome失败,或者是否有其他原因对chrome更好的原因?谢谢!
Crashalot

@ajwaka至少在今天,此代码似乎可以在chrome上运行,因此出现了问题。
Crashalot

@Crashalot-您问的是我6年前回答的问题-很遗憾,我不再想起这种情况了,浏览器在6年中走了很长一段路。
ajwaka

40

我尝试了上面的许多示例,但无法使它们与Chrome一起使用。这种简单的方法似乎适用于Chrome 39,Firefox 34,Safari 5.1.7和IE11。这是我们JS库中的代码段。

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

1
@Surendra,请您指定“不工作”的意思吗?解析时出错?运行时出错?弹出窗口打开,但标记为已阻止?弹出窗口被阻止,但标记为打开?我没有看到任何原因导致资源管理器无法解决这个问题,除非在这种情况下允许在NULL上调用focus(),否则在尝试之前对NULL进行测试就可以了。
FrancescoMM

即使弹出窗口成功,IE始终返回null。
德文·加纳

34

更新:弹出窗口存在于非常古老的时代。最初的想法是在不关闭主窗口的情况下显示其他内容。到目前为止,还有其他方法可以执行此操作:JavaScript能够发送服务器请求,因此很少使用弹出窗口。但是有时候它们仍然很方便。

过去,恶意网站经常滥用弹出式窗口。错误的页面可能会打开大量带有广告的弹出窗口。因此,现在大多数浏览器都尝试阻止弹出窗口并保护用户。

如果在用户触发的事件处理程序(例如onclick)之外调用大多数浏览器,则会阻止弹出窗口。

如果您考虑一下,那会有些棘手。如果代码直接在onclick处理程序中,则很简单。但是在setTimeout中打开的弹出窗口是什么?

试试这个代码:

 // open after 3 seconds
setTimeout(() => window.open('http://google.com'), 3000);

弹出窗口在Chrome中打开,但在Firefox中被阻止。

…这在Firefox中也适用:

 // open after 1 seconds
setTimeout(() => window.open('http://google.com'), 1000);

区别在于,Firefox将超时时间定为2000ms或更短是可以接受的,但是在此之后,假定现在不在用户操作范围内,则删除“信任”。因此,第一个被阻止,第二个没有被阻止。


2012年最新的原始答案:

此弹出窗口阻止程序检查解决方案已在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);

希望这可以帮助!:)


20
我认为您需要更多下划线
Jacob Stamm,

在firefox中,这将显示空白页面,您甚至无法在打开器页面上看到弹出窗口阻止程序消息。如何关闭空白页?
user460114 '18

请注意,如果弹出URL是可下载的文件(Content-Disposition: attachment;在响应标头中),则弹出窗口将立即关闭,因此setTimeout代码将失败,并且浏览器将抱怨“启用了弹出窗口阻止程序!”。对于Chrome,我推荐@DanielB的解决方案,它的效果很好。
wonsuc

1
@wonsuc打开带有Content-Disposition: attachment;标题的链接时,不需要在弹出窗口中将其打开。只需直接链接到您要下载的资产,浏览器的本机行为将允许您下载而无需重定向您离开当前页面。
凯文B

@KevinB我必须说我处于特定情况下。我必须下载多个文件,这些文件会从HTML生成PDF文件。而且,如果HTML内容很大,有时会花费几秒钟,如果我使用window.location它,则如果第一个文件生成的时间太长,则在第二个请求开始时它将被忽略。这就是我必须使用的原因window.open,因为window.location从不让我知道响应何时完成。
wonsuc

12

无论浏览器公司或版本如何,始终可以使用的一种“解决方案” 是,在屏幕上的警告信息仅出现在控件附近,该控件会弹出一个窗口,礼貌地警告用户该操作需要弹出窗口,并请为网站启用它们。

我知道这不是花哨的东西,但它无法简化,只需要大约5分钟的测试,然后您就可以进行其他噩梦了。

用户允许您的网站弹出窗口后,如果您不过度使用弹出窗口,也将是体贴的。您想要做的最后一件事就是惹恼您的访客。


1
不幸的是,有时此问题中的所有其他解决方案都是不可接受的-仅此一种。为什么?因为它们都尝试显示弹出窗口-而不只是检测是否启用了弹出窗口。如果我想安静地做该怎么办?
Sagi Mann

这里还要记住的一点是,用户不能总是仅为您的站点启用弹出窗口。例如,在较早版本的safari中,用户只能完全启用或禁用弹出窗口阻止程序,没有白名单可用。
Jeremy

1

我结合了@Kevin B和@DanielB的解决方案。
这要简单得多。

var isPopupBlockerActivated = function(popupWindow) {
    if (popupWindow) {
        if (/chrome/.test(navigator.userAgent.toLowerCase())) {
            try {
                popupWindow.focus();
            } catch (e) {
                return true;
            }
        } else {
            popupWindow.onload = function() {
                return (popupWindow.innerHeight > 0) === false;
            };
        }
    } else {
        return true;
    }
    return false;
};

用法:

var popup = window.open('https://www.google.com', '_blank');
if (isPopupBlockerActivated(popup)) {
    // Do what you want.
}

1
isPopupBlockerActivated 函数从不返回return (popupWindow.innerHeight > 0) === false;。当您的浏览器不是Chrome时,您的函数返回false。因为onload是异步过程。您的函数返回false,然后执行onload,但其结果永不返回。
OnurGazioğlu19-4-12的

0

我已经尝试了很多解决方案,但是我唯一能想到的解决方案也可以与uBlock Origin一起使用,那就是利用超时检查弹出窗口的关闭状态。

function popup (url, width, height) {
    const left = (window.screen.width / 2) - (width / 2)
    const top = (window.screen.height / 2) - (height / 2)
    let opener = window.open(url, '', `menubar=no, toolbar=no, status=no, resizable=yes, scrollbars=yes, width=${width},height=${height},top=${top},left=${left}`)

    window.setTimeout(() => {
        if (!opener || opener.closed || typeof opener.closed === 'undefined') {
            console.log('Not allowed...') // Do something here.
        }
    }, 1000)
}

显然,这是黑客。像所有解决此问题的方法一样。

您需要在setTimeout中提供足够的时间来考虑初始的打开和关闭,因此永远不会完全准确。这将是反复试验的位置。

将此添加到您的尝试列表。


0

如果您还拥有子代码一种简单的方法是在其html中创建一个简单的变量,如下所示:

    <script>
        var magicNumber = 49;
    </script>

然后从父级检查其存在,类似于以下内容:

    // Create the window with login URL.
    let openedWindow = window.open(URL_HERE);

    // Check this magic number after some time, if it exists then your window exists
    setTimeout(() => {
        if (openedWindow["magicNumber"] !== 32) {
            console.error("Window open was blocked");
        }
    }, 1500);

我们等待一段时间以确保网页已加载,然后检查其存在。显然,如果窗口在1500毫秒后未加载,则该变量仍为undefined


-1

通过使用onbeforeunload事件,我们可以进行如下检查

    function popup()
    {
        var chk=false;
        var win1=window.open();
        win1.onbeforeunload=()=>{
            var win2=window.open();
            win2.onbeforeunload=()=>{
                chk=true;
            };
        win2.close();
        };
        win1.close();
        return chk;
    }

它将在背景中打开2个黑色窗口

该函数返回布尔值。

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.