避免浏览器弹出窗口阻止程序


172

我正在纯粹用JavaScript开发OAuth身份验证流程,我想在弹出窗口中向用户显示“授予访问权限”窗口,但该窗口被阻止了。

如何防止由window.open或创建的弹出窗口window.showModalDialog被不同浏览器的弹出窗口阻止程序阻止?


11
即使有可能(我不知道),如果人们使用弹出窗口阻止程序,您也应该尊重它。当站点尝试打开弹出窗口时,大多数浏览器都会显示一条消息,以便在需要时仍可以看到该消息。您可以在您的站点上标记为某些内容会在弹出窗口中打开,用户应该允许它以便继续。
菲利克斯·克林

5
最佳做法如下:1)成功执行此操作2)关上窗户,禁止门,畏缩于不安的网络顾客聚集的恐惧中3)pent悔,取下弹出式胸围,并尊重您的听众。
Alex Mcp 2010年

亚历克斯和费利克斯,我已经更新了问题。我不会将知识用于邪恶:)。谢谢!
Pablo Fernandez

9
我想补充一点,绕过弹出窗口阻止程序实际上可能是在尝试改善用户体验。在我现在正在处理的示例中,我们正在使用Javascript应用程序(基于ExtJS),并且试图让用户使用Paypal付款。我们为他们提供了一个按钮,他们可以单击该按钮以在新窗口中启动贝宝,但是IE的某些版本会将其阻止为弹出窗口(即使单击按钮也是如此)。如果它们现在启用了弹出窗口,则屏幕将重新加载,并且作为JavaScript应用程序,我们将失去窗口状态,因此必须重新开始。确实如此:问题在于IE太笨了。
NateDSaint 2012年

1
@FelixKling是的,有可能。浏览器制造商已经考虑过这一点。只要有用户意图,就可以打开一个弹出窗口(通过用户单击链接或按钮来发出信号)。弹出窗口阻止程序应尊重用户的意图。如果IE的弹出窗口阻止程序没有,则是弹出窗口阻止程序有问题。用户使用弹出窗口阻止程序来防止脚本随意打开弹出窗口,而不是阻止他们自己尝试打开的弹出窗口(通过单击按钮或链接)。
Stijn de Witt

Answers:


286

一般规则是,如果window.open不是直接用户操作调用的javascript调用了javascript或类似方法,则会阻止弹出窗口阻止程序。也就是说,您可以window.open响应单击按钮而调用,而不会被弹出窗口阻止程序击中,但是如果将相同的代码放入计时器事件中,它将被阻止。呼叫链深度也是一个因素-一些较旧的浏览器仅查看直接呼叫者,较新的浏览器可以稍微回溯以查看呼叫者的呼叫者是否是鼠标单击等。请使其尽可能浅,以避免弹出窗口阻止程序。


2
有趣的是,通过绑定到select元素的change事件启动的弹出窗口将被阻止(在Chrome中,不是FF),即使该事件是由直接的用户操作(如单击)启动的。尽管如果绑定到输入,则允许它们。奇怪。
ccnokes

6
没有人说浏览器是一致的。:P
dthorpe 2014年

8
通过实验,我必须了解堆栈深度与弹出窗口阻止程序无关。它实际上检查是否在用户操作后1秒钟内调用window.open。测试在Chrome 46和Firefox 42
Mesqalito

可以在两种浏览器中规避1秒钟的超时,从而可以使用此页面上的@ tj-crowder给出的答案来无限期地使用..让您通过ajax调用的URL是一些使用sleep( )在返回响应之前的一段时间。浏览器在“加载”页面时将挂起。然后在收到响应时触发弹出窗口。但是,在Chrome浏览器中,必须在ajax()之前添加一个alert()才能使此技巧起作用。
歌颂节目

184

基于Jason Sebring非常有用的技巧,以及在这里那里所涉及的内容,我为我的案例找到了一个完美的解决方案:

带有Javascript代码段的伪代码:

  1. 立即根据用户操作创建空白弹出窗口

    var importantStuff = window.open('', '_blank');

    可选:添加一些“正在等待”的信息消息。例子:

    a)外部HTML页面:将以上行替换为

    var importantStuff = window.open('http://example.com/waiting.html', '_blank');

    b)文字:在上述内容下方添加以下行:

    importantStuff.document.write('Loading preview...');
  2. 准备就绪时将其填充内容(例如,返回AJAX调用时)

    importantStuff.location.href = 'http://shrib.com';

window.open使用您需要的其他任何选项来丰富呼叫。

我实际上使用此解决方案进行mailto重定向,并且在我所有的浏览器(Windows 7,Android)上都可以使用。该_blank位有助于mailto重定向在移动设备btw上工作。

你的经验?有什么办法可以改善?


1
?因此,如果不是来自浏览器中的用户操作,该怎么办?以我的示例为例,在用户针对服务器进行身份验证之后,它必须打开一个新标签页
Don Cheadle 2015年

@mmcrae不要那样做。无论您打算做什么,都有比弹出窗口更好的方法。否则,很可能我永远也不想看到您的网站。当今的浏览器确保您无法执行此操作-请参阅@dthorpe的答案
瑞士先生

5
Whatever it is you intend to do, there is a better way than a popup window大声笑?奇怪的概括。客户希望他们通过身份验证的页面保持打开状态,并希望通过身份验证后的新站点/登录页面在新选项卡中打开。是的,不是我关于出色的用户体验的想法……但这似乎是合理的
Don Cheadle

@mmcrae。坐下来认真思考。我保证您会在您描述的场景中找到一个“用户操作”。我的回答的全部要点是,当您执行用户操作时创建弹出窗口-然后在其中填充内容。您的情况的提示:用户点击“验证”->创建弹出窗口(空);计时器启动或服务器响应返回,或其他->将内容填充到弹出窗口中。
瑞士先生

3
有用的提示,如果ajax请求失败,请调用importantStuff.close以关闭新选项卡,并在原始页面中提供并发出警报。

24

除了瑞士先生的帖子,在我的情况下,window.open是在promise中启动的,它打开了弹出窗口阻止程序,我的解决方案是:

$scope.gotClick = function(){

  var myNewTab = browserService.openNewTab();
  someService.getUrl().then(
    function(res){
        browserService.updateTabLocation(res.url, myNewTab);

    }
  );
};

browserService:

this.openNewTab = function(){
     var newTabWindow = $window.open();
     return newTabWindow;
}

this.updateTabLocation = function(tabLocation, tab) {
     if(!tabLocation){
       tab.close();
     }
     tab.location.href = tabLocation;
}

这是您可以使用Promise响应而不调用弹出窗口阻止程序来打开新选项卡的方法。


1
这导致了我的解决方案!我在其中创建了一个包含打开的选项卡的变量,然后在加载数据后填充了URL。谢谢。const tab = window.open(); observable.subscribe(dataUrl => tab.location.href = dataUrl);
jonas

1
如果您启用了弹出窗口阻止程序,则无法解决弹出窗口阻止程序的问题...
Alejandro Vales

@Alejandro Vales jonas解决方案仅在代码将通过onClick事件或任何用户交互运行时才有效。当您尝试通过windows.open在promise,timeout,subscribe中打开新选项卡时,浏览器认为这是对用户的一种操纵,因此解决方案是在输入promise之前创建一个实例,在其中进行更改像jonas一样的href
戴维

@David非常感谢!!!我没碰巧看到.then当时的答案,这就是为什么我如此困惑的原因:/ SRY ...
Alejandro Vales

@David这太好了!奇迹般有效。如果我可以再问一个问题来打扰您-您也知道如何在Edge中进行这项工作吗?轻推正确的资源将极大地有助于...
dzenesiz

21

作为一个好的实践,我认为最好测试弹出窗口是否被阻止并采取措施以防万一。您需要知道window.open有一个返回值,如果操作失败,该值可能为null。例如,在以下代码中:

function pop(url,w,h) {
    n=window.open(url,'_blank','toolbar=0,location=0,directories=0,status=1,menubar=0,titlebar=0,scrollbars=1,resizable=1,width='+w+',height='+h);
    if(n==null) {
        return true;
    }
    return false;
}

如果弹出窗口被阻止,则window.open将返回null。因此该函数将返回false。

例如,假设直接从任何链接调用此函数target="_blank":如果成功打开了弹出窗口,则return false将阻止链接操作,否则,如果弹出窗口被阻止,则return true将让默认行为(打开新的_blank窗口)并继续。

<a href="http://whatever.com" target="_blank" onclick='return pop("http://whatever.com",300,200);' >

这样,您将有一个弹出窗口(如果可以),以及一个_blank窗口(如果没有)。

如果弹出窗口没有打开,您可以:

  • 像示例中一样打开一个空白窗口,然后继续
  • 打开一个伪造的弹出窗口(页面内的iframe)
  • 通知用户(“请允许该站点弹出窗口”)
  • 打开一个空白窗口,然后通知用户等。

谢谢。工作了!
Bcktr

8

来自Google的oauth JavaScript API:

http://code.google.com/p/google-api-javascript-client/wiki/Authentication

查看读取的区域:

设置身份验证

OAuth 2.0的客户端实现使用弹出窗口提示用户登录并批准该应用程序。第一次调用gapi.auth.authorize可以触发弹出窗口阻止程序,因为它间接打开了弹出窗口。为防止弹出窗口阻止程序在auth调用上触发,请在客户端加载时调用gapi.auth.init(callback)。库准备好进行身份验证调用时,将执行提供的回调。

我猜想它与上面的真实答案有关,它解释了如果有立即响应,它将不会触发弹出警报。“ gapi.auth.init”正在制作,因此api立即发生。

实际应用

我使用npm上的节点通行证以及每个提供商的各种通行证软件包制作了一个开源身份验证微服务。我对第三方使用了一种标准的重定向方法,为它提供了重定向URL以供返回。这是编程式的,因此在登录/注册时以及在特定页面上,我可以有不同的位置重定向回。

github.com/sebringj/athu

passwordjs.org


3

我尝试了多种解决方案,但他是所有浏览器中唯一对我有效的解决方案

let newTab = window.open(); newTab.location.href = url;


2
这对于启用了弹出窗口阻止程序的用户不起作用
Alejandro Vales

是什么url?它没有分配。
shinriyo

@shinriyo url是指向您想要访问的任何页面的链接,例如http://example.com
pomobc

@AlejandroVales我启用了弹出窗口阻止程序,并且可以正常工作。问题是window.open()无法以编程方式打开新窗口,如果需要,该答案是选项之一。使用newTab我们引用的变量window.open(),以后我们可以调用它,插入url我们需要的变量(在我的情况下为某些blob的url),新选项卡将在输入的url上打开。
stanimirsp

0

除非回调成功返回,否则我不想创建新页面,因此我这样做是为了模拟用户单击:

function submitAndRedirect {
  apiCall.then(({ redirect }) => {
      const a = document.createElement('a');
      a.href = redirect;
      a.target = '_blank';
      document.body.appendChild(a);
      a.click();
      document.body.removeChild(a);
  });
}

3
在Chrome 62中对我不起作用。弹出窗口(页面)被阻止。
s.ermakovich

1
是的,您是对的-我也发现这是不一致的。我最终使我的api调用同步化
user3479425

-8

摆脱这种情况的最简单方法是:

  1. 不要使用document.open()。
  2. 而是使用this.document.location.href = location; 位置是要加载的网址

例如:

<script>
function loadUrl(location)
{
this.document.location.href = location;
}</script>

<div onclick="loadUrl('company_page.jsp')">Abc</div>

这对我来说非常有效。干杯


2
在新标签页中打开网址怎么办?
3条规则
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.