避免浏览器弹出窗口拦截器

IT技术 javascript popup modal-dialog popup-blocker
2021-01-27 13:02:18

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

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

6个回答

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

可以在两个浏览器中规避 1 秒超时,允许使用此页面上@tj-crowder 的答案无限期地使用..让您通过 ajax 调用的 URL 是一些使用 sleep( ) 在它返回响应之前的一段时间。浏览器将在“加载”页面时挂起......然后在收到响应时触发弹出窗口。但是,在 Chrome 中,您必须在 ajax() 之前添加一个 alert() 才能使这个技巧起作用。
2021-03-22 13:02:18
有趣的是,通过绑定到 select 元素的更改事件启动的弹出窗口将被阻止(在 Chrome 中,而不是 FF),即使该事件是由直接用户操作启动的,例如单击。虽然如果绑定到输入,它们是允许的。奇怪的。
2021-03-24 13:02:18
通过实验,我必须明白堆栈深度与弹出窗口阻止程序无关。它实际上检查是否在用户操作后 1 秒内调用 window.open。在 Chrome 46 和 Firefox 42 中测试。
2021-03-24 13:02:18
没有人说浏览器是一致的。:P
2021-03-26 13:02:18

基于Jason Sebring非常有用的提示,以及这里那里涵盖的内容,我为我的案例找到了一个完美的解决方案:

带有 Javascript 片段的伪代码:

  1. 立即在用户操作上创建一个空白弹出窗口

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

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

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

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

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

    b) 文本:在上面一行下面添加以下行:

     importantStuff.document.write('Loading preview...');
    
  2. 准备好时用内容填充它(例如,当返回 AJAX 调用时)

     importantStuff.location.href = 'https://example.com/finally.html';
    

    或者,如果您根本不需要它,您可以在此处关闭窗口(if ajax request fails例如 - 感谢@Goose 的评论):

     importantStuff.close();
    

我实际上将这个解决方案用于 mailto 重定向,它适用于我的所有浏览器(Windows 7、Android)。_blank位有助于mailto重定向在移动设备上工作,顺便说一句。

Whatever it is you intend to do, there is a better way than a popup window哈哈?奇怪的概括。客户希望他们进行身份验证的页面保持打开状态,并且身份验证后的新站点/登录页面在新选项卡中打开。是的,这不是我对出色用户体验的想法……但这似乎是合理的
2021-03-11 13:02:18
? 那么如果它不是来自浏览器中的用户操作,你会怎么做?对于我的示例,在用户对服务器进行身份验证后,它必须打开一个新选项卡
2021-03-24 13:02:18
@mmcrae。坐下来认真思考。我保证你会在你描述的场景中找到一个“用户操作”。我的回答的重点是当您有用户操作时创建弹出窗口- 然后稍后用内容填充它。提示您的情况:用户点击“身份验证”-> 创建弹出窗口(空);计时器已启动或服务器响应已返回或其他任何 -> 将内容填充到弹出窗口中。
2021-03-24 13:02:18
有用的提示,如果 ajax 请求失败,调用importantStuff.close关闭新选项卡并在原始页面中提供和提醒。
2021-04-08 13:02:18
我真的很感激这个解决方案。它工作正常。改进此解决方案的一种方法是在几秒钟后自动关闭的加载页面上添加一个脚本。对于我的用例,这是更好的行为。谢谢!
2021-04-09 13:02:18

作为一个很好的做法,我认为测试弹出窗口是否被阻止并采取措施以防万一是个好主意您需要知道 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":如果弹出窗口成功打开,返回 false将阻止链接操作,否则如果弹出窗口被阻止,返回true将让默认行为(打开新的 _blank 窗口)并继续.

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

这样你就会有一个弹出窗口,如果它有效,一个 _blank 窗口如果没有。

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

  • 在示例中打开一个空白窗口并继续
  • 打开一个虚假的弹出窗口(页面内的 iframe)
  • 通知用户(“请允许此站点的弹出窗口”)
  • 打开一个空白窗口,然后通知用户等。
谢谢你。工作了!
2021-03-18 13:02:18

此外,Swiss Mister post,在我的情况下,window.open是在一个 promise 内启动的,它打开了弹出窗口阻止程序,我的解决方案是:在 angular 中:

$scope.gotClick = function(){

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

    }
  );
};

浏览器服务:

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

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

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

@David 这太棒了!奇迹般有效。如果我能再问一个问题来打扰你——你也知道如何在 Edge 中做到这一点吗?轻推正确的资源将极大地帮助...
2021-03-21 13:02:18
@David 非常感谢您!!!我没有碰巧看到.thenon then 的答案,这就是我如此困惑的原因:/ SRY ...
2021-03-23 13:02:18
这导致了我的解决方案!在那里我创建了一个包含打开的选项卡的变量,然后在数据加载后填充 url。谢谢。const tab = window.open(); observable.subscribe(dataUrl => tab.location.href = dataUrl);
2021-03-31 13:02:18
如果您启用了弹出窗口阻止程序,这将无法解决弹出窗口阻止程序的问题...
2021-04-03 13:02:18
@Alejandro Vales jonas 解决方案只有在代码从 onClick 事件或任何用户交互中运行时才有效。当您尝试通过 windows.open 在Promise中打开一个新选项卡时,超时,订阅...浏览器认为这是对用户的操作,因此解决方案是在输入Promise之前创建一个实例,在您内部进行更改像乔纳斯一样的href
2021-04-03 13:02:18

来自 Google 的 oauth JavaScript API:

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

看到它写的区域:

设置身份验证

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

我猜它与上面的真实答案有关,它如何解释是否有立即响应,它不会触发弹出警报。“gapi.auth.init”正在制作它以便api立即发生。

实际应用

我使用 npm 上的节点通行证和每个提供商的各种通行证包制作了一个开源身份验证微服务。我对第 3 方使用了标准的重定向方法,并为其提供了一个重定向 URL 以供返回。这是程序化的,所以如果登录/注册和特定页面上,我可以有不同的地方重定向回。

github.com/sebringj/athu

护照网站