Javascript 避免浏览器弹出窗口拦截器
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2587677/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Avoid browser popup blockers
提问by Pablo Fernandez
I'm developing an OAuth authentication flow purely in JavaScript and I want to show the user the "grant access" window in a popup, but it gets blocked.
我正在纯粹用 JavaScript 开发 OAuth 身份验证流程,我想在弹出窗口中向用户显示“授予访问权限”窗口,但它被阻止了。
How can I prevent pop up windows created by either window.openor window.showModalDialogfrom being blocked by the different browsers' pop-up blockers?
如何防止由不同浏览器的弹出窗口阻止程序创建window.open或阻止的弹出窗口window.showModalDialog?
回答by dthorpe
The general rule is that popup blockers will engage if window.openor similar is invoked from javascript that is not invoked by direct user action. That is, you can call window.openin response to a button click without getting hit by the popup blocker, but if you put the same code in a timer event it will be blocked. Depth of call chain is also a factor - some older browsers only look at the immediate caller, newer browsers can backtrack a little to see if the caller's caller was a mouse click etc. Keep it as shallow as you can to avoid the popup blockers.
一般规则是,如果window.open从 javascript 调用或类似的调用,而不是通过直接用户操作调用,则弹出窗口阻止程序将参与。也就是说,您可以调用window.open以响应按钮单击而不会被弹出窗口阻止程序击中,但是如果您将相同的代码放入计时器事件中,它将被阻止。调用链的深度也是一个因素 - 一些较旧的浏览器只查看直接调用者,较新的浏览器可以回溯一点,看看调用者的调用者是否是鼠标点击等。尽可能保持浅层以避免弹出窗口阻止程序。
回答by Swiss Mister
Based on Jason Sebring's very useful tip, and on the stuff covered hereand there, I found a perfect solution for my case:
基于Jason Sebring的非常有用的提示,以及这里和那里涵盖的内容,我为我的案例找到了一个完美的解决方案:
Pseudo code with Javascript snippets:
带有 Javascript 片段的伪代码:
immediately create a blank popup on user action
var importantStuff = window.open('', '_blank');Optional: add some "waiting" info message. Examples:
a) An external HTML page: replace the above line with
var importantStuff = window.open('http://example.com/waiting.html', '_blank');b) Text: add the following line below the above one:
importantStuff.document.write('Loading preview...');fill it with content when ready (when the AJAX call is returned, for instance)
importantStuff.location.href = 'http://shrib.com';
立即在用户操作上创建一个空白弹出窗口
var importantStuff = window.open('', '_blank');可选:添加一些“等待”信息消息。例子:
a) 外部 HTML 页面:将上面的行替换为
var importantStuff = window.open('http://example.com/waiting.html', '_blank');b) 文本:在上面一行下面添加以下行:
importantStuff.document.write('Loading preview...');准备好时用内容填充它(例如,当返回 AJAX 调用时)
importantStuff.location.href = 'http://shrib.com';
Enrich the call to window.openwith whatever additional options you need.
window.open使用您需要的任何其他选项丰富呼叫。
I actually use this solution for a mailto redirection, and it works on all my browsers (windows 7, Android). The _blankbit helps for the mailto redirection to work on mobile, btw.
我实际上将这个解决方案用于 mailto 重定向,它适用于我所有的浏览器(Windows 7、Android)。该_blank位有助于mailto重定向在移动设备上工作,顺便说一句。
Your experience? Any way to improve this?
你的经历?有什么办法可以改善这种情况吗?
回答by David
In addition Swiss Mister post, in my case the window.openwas launched inside a promise, which turned the popup blocker on, my solution was: in angular:
此外,Swiss Mister post,在我的情况下,window.open是在一个 promise 中启动的,它打开了弹出窗口阻止程序,我的解决方案是:在 angular 中:
$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;
}
this is how you can open a new tab using the promise response and not invoking the popup blocker.
这就是您可以使用承诺响应而不调用弹出窗口阻止程序打开新选项卡的方法。
回答by FrancescoMM
As a good practice I think it is a good idea to testif a popup was blocked and take action in case. You need to know that window.open has a return value, and that value may be null if the action failed. For example, in the following code:
作为一个很好的做法,我认为测试弹出窗口是否被阻止并采取措施以防万一是个好主意。您需要知道 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;
}
if the popup is blocked, window.open will return null. So the function will return false.
如果弹出窗口被阻止,window.open 将返回 null。所以函数会返回false。
As an example, imagine calling this function directly from any link with
target="_blank": if the popup is successfully opened, returningfalsewill block the link action, else if the popup is blocked, returningtruewill let the default behavior (open new _blank window) and go on.
举个例子,想象一下直接从任何链接调用这个函数
target="_blank":如果弹出窗口成功打开,返回false将阻止链接操作,否则如果弹出窗口被阻止,返回true将让默认行为(打开新的_blank窗口)并继续.
<a href="http://whatever.com" target="_blank" onclick='return pop("http://whatever.com",300,200);' >
This way you will have a popup if it works, and a _blank window if not.
这样你就会有一个弹出窗口,如果它有效,一个 _blank 窗口如果没有。
If the popup does not open, you can:
如果弹出窗口没有打开,您可以:
- open a blank window like in the example and go on
- open a fake popup (an iframe inside the page)
- inform the user ("please allow popups for this site")
- open a blank window and then inform the user etc..
- 像示例中一样打开一个空白窗口并继续
- 打开一个假弹出窗口(页面内的 iframe)
- 通知用户(“请允许此站点的弹出窗口”)
- 打开一个空白窗口,然后通知用户等。
回答by Jason Sebring
from Google's oauth JavaScript API:
来自 Google 的 oauth JavaScript API:
http://code.google.com/p/google-api-javascript-client/wiki/Authentication
http://code.google.com/p/google-api-javascript-client/wiki/Authentication
See the area where it reads:
看到它写的区域:
Setting up Authentication
设置身份验证
The client's implementation of OAuth 2.0 uses a popup window to prompt the user to sign-in and approve the application. The first call to gapi.auth.authorize can trigger popup blockers, as it opens the popup window indirectly. To prevent the popup blocker from triggering on auth calls, call gapi.auth.init(callback) when the client loads. The supplied callback will be executed when the library is ready to make auth calls.
OAuth 2.0 客户端的实现使用一个弹出窗口来提示用户登录并批准应用程序。第一次调用 gapi.auth.authorize 可以触发弹出窗口阻止程序,因为它间接打开了弹出窗口。为了防止弹出窗口阻止程序在身份验证调用时触发,请在客户端加载时调用 gapi.auth.init(callback)。当库准备好进行身份验证调用时,将执行提供的回调。
I would guess its relating to the real answer above in how it explains if there is an immediate response, it won't trip the popup alarm. The "gapi.auth.init" is making it so the api happens immediately.
我猜它与上面的真实答案有关,它如何解释是否有立即响应,它不会触发弹出警报。“gapi.auth.init”正在制作它以便api立即发生。
Practical Application
实际应用
I made an open source authentication microservice using node passport on npm and the various passport packages for each provider. I used a standard redirect approach to the 3rd party giving it a redirect URL to come back to. This was programmatic so I could have different places to redirect back to if login/signup and on particular pages.
我使用 npm 上的节点通行证和每个提供商的各种通行证包制作了一个开源身份验证微服务。我对第 3 方使用了标准的重定向方法,并为其提供了一个重定向 URL 以供返回。这是程序化的,所以如果登录/注册和特定页面上,我可以有不同的地方重定向回。
回答by pomobc
I tried multiple solutions, but his is the only one that actually worked for me in all the browsers
我尝试了多种解决方案,但他是唯一一个在所有浏览器中都对我有用的解决方案
let newTab = window.open();
newTab.location.href = url;
let newTab = window.open();
newTab.location.href = url;
回答by user3479425
I didn't want to make the new page unless the callback returned successfully, so I did this to simulatethe user click:
除非回调成功返回,否则我不想制作新页面,所以我这样做是为了模拟用户点击:
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);
});
}
回答by Pramod Shetty
The easiest way to get rid of this is to:
摆脱这种情况的最简单方法是:
- Dont use document.open().
- Instead use this.document.location.href = location; where location is the url to be loaded
- 不要使用 document.open()。
- 而是使用 this.document.location.href = location; 其中 location 是要加载的 url
Ex :
前任 :
<script>
function loadUrl(location)
{
this.document.location.href = location;
}</script>
<div onclick="loadUrl('company_page.jsp')">Abc</div>
This worked very well for me. Cheers
这对我来说非常有效。干杯

