我知道javascript技术可以检测弹出窗口是否在其他浏览器中被阻止(如the answer to this question中所述)。这是基本测试:
var newWin = window.open(url);
if(!newWin || newWin.closed || typeof newWin.closed=='undefined')
{
//POPUP BLOCKED
}
但这在Chrome中不起作用。弹出窗口被阻止时,永远不会到达“POPUP BLOCKED”部分。
当然,测试工作到一定程度,因为Chrome实际上并没有阻止弹出窗口,而是在右下角的一个微小的窗口中打开它,列出“阻塞”弹出窗口。
我想要做的是能够判断弹出窗口是否被Chrome的弹出窗口拦截器阻止。我试图避免浏览器嗅探,以支持功能检测。有没有办法在没有浏览器嗅探的情况下做到这一点?
修改:我现在尝试使用newWin.outerHeight
,newWin.left
和其他类似属性来完成此任务。当弹出窗口被阻止时,Google Chrome会将所有位置和高度值返回为0。
不幸的是,即使弹出窗口实际打开了一段未知的时间,它也会返回相同的值。经过一段神奇的时期(在测试中几秒钟),位置和大小信息将作为正确的值返回。换句话说,我仍然没有更接近解决这个问题。任何帮助将不胜感激。
答案 0 :(得分:62)
你所说的“神奇时间”可能就是弹出的DOM被加载的时候。或者可能是在加载了所有内容(图像,外置CSS等)之后。您可以通过在弹出窗口中添加一个非常大的图形来轻松测试它(首先清除缓存!)。如果您使用的是JQuery框架(如jQuery(或类似的东西)),您可以使用ready()事件(或类似的东西)在检查窗口偏移量之前等待DOM加载。这样做的危险在于Safari检测以一种冲突的方式工作:在Safari中,弹出窗口的DOM永远不会就绪(因为它会为你试图打开的窗口提供一个有效的句柄 - 无论它实际打开还是不。 (事实上,我相信你上面的弹出测试代码不适用于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秒。在子窗口中,您需要添加测试函数:
function test(){}
弹出窗口阻止程序检测器测试“test”函数是否作为子窗口的成员存在。
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)
});
希望这有帮助。
答案 1 :(得分:15)
对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);
};
}
答案 2 :(得分:11)
以下是弹出窗口拦截器检查的 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);
希望这有帮助! :)
答案 3 :(得分:10)
Rich的答案不再适用于Chrome。看起来Chrome现在在弹出窗口中实际执行任何Javascript。我最终检查screenX值为0以检查阻止的弹出窗口。我也认为我找到了一种方法来保证这个属性在检查之前是最终的。这仅适用于您域上的弹出窗口,但您可以添加如下的onload处理程序:
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);
};
}
正如许多人所报告的那样,即使在onload之后,“screenX”属性有时会报告失败的弹出窗口非零。我也遇到过这种情况,但如果在零ms超时后添加检查,则screenX属性似乎总是输出一致的值。
如果有办法让这个脚本更健壮,请告诉我。似乎可以为我的目的而工作。
答案 4 :(得分:9)
这对我有用:
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。
答案 5 :(得分:4)
我将复制/粘贴此处提供的答案:Daniel https://stackoverflow.com/a/27725432/892099。适用于铬40,非常干净。没有肮脏的黑客或等待涉及。
function popup(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.");
}
}
答案 6 :(得分:2)
检查窗口相对于父窗口的位置。 Chrome使窗口几乎显示在屏幕外。
答案 7 :(得分:2)
我有一个类似的问题,弹出窗口没有在Chrome中打开。我很沮丧,因为我没有试图偷偷摸摸地做某事,比如onload弹出窗口,只是在用户点击时打开一个窗口。我很沮丧,因为运行我的函数,包括来自firebug命令行的window.open()工作,而实际点击我的链接没有!这是我的解决方案:
错误的方法:从事件侦听器运行window.open()(在我的例子中,dojo.connect到DOM节点的onclick事件方法)。
dojo.connect(myNode, "onclick", function() {
window.open();
}
正确方法:将函数分配给调用window.open()的节点的onclick属性。
myNode.onclick = function() {
window.open();
}
当然,如果需要,我仍然可以为同一个onclick事件做事件监听器。通过此更改,即使Chrome设置为“不允许任何网站显示弹出窗口”,我也可以打开我的窗口。喜悦。
如果有人明智地告诉我们其他人为什么会有所作为,我很乐意听到它,虽然我怀疑它只是试图关闭恶意程序弹出窗口。
答案 8 :(得分:2)
这是目前在Chrome中使用的版本。尽管我添加了一个处理时间的包装器,但只是与Rich的解决方案稍作改动。
function checkPopupBlocked(poppedWindow) {
setTimeout(function(){doCheckPopupBlocked(poppedWindow);}, 5000);
}
function doCheckPopupBlocked(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.outerWidth == 0) {
// This is usually Chrome's doing. The outerWidth (and most other size/location info)
// will be left at 0, EVEN THOUGH the contents of the popup will exist (including the
// test function we check for next). The outerWidth starts as 0, so a sufficient delay
// after attempting to pop is needed.
result = true;
}
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);
//}
}
if(result)
alert("The popup was blocked. You must allow popups to use this site.");
}
要使用它,请执行以下操作:
var popup=window.open('location',etc...);
checkPopupBlocked(popup);
如果弹出窗口被阻止,则会在5秒宽限期后显示警告消息(您可以调整,但5秒应该非常安全)。
答案 9 :(得分:2)
这个片段包含了以上所有内容 - 由于某种原因 - StackOverflow排除了下面代码块中的第一行和最后一行代码,所以我写了一篇博客。有关完整说明以及(可下载)代码的其余部分,请查看 my blog at thecodeabode.blogspot.com
var PopupWarning = {
init : function()
{
if(this.popups_are_disabled() == true)
{
this.redirect_to_instruction_page();
}
},
redirect_to_instruction_page : function()
{
document.location.href = "http://thecodeabode.blogspot.com";
},
popups_are_disabled : function()
{
var popup = window.open("http://localhost/popup_with_chrome_js.html", "popup_tester", "width=1,height=1,left=0,top=0");
if(!popup || popup.closed || typeof popup == 'undefined' || typeof popup.closed=='undefined')
{
return true;
}
window.focus();
popup.blur();
//
// Chrome popup detection requires that the popup validates itself - so we need to give
// the popup time to load, then call js on the popup itself
//
if(navigator && (navigator.userAgent.toLowerCase()).indexOf("chrome") > -1)
{
var on_load_test = function(){PopupWarning.test_chrome_popups(popup);};
var timer = setTimeout(on_load_test, 60);
return;
}
popup.close();
return false;
},
test_chrome_popups : function(popup)
{
if(popup && popup.chrome_popups_permitted && popup.chrome_popups_permitted() == true)
{
popup.close();
return true;
}
//
// If the popup js fails - popups are blocked
//
this.redirect_to_instruction_page();
}
};
PopupWarning.init();
答案 10 :(得分:2)
Mine使用回调架构,当弹出窗口被阻止时会发送true
,否则会false
。
window.isPopupBlocked = function(popup_window, cb)
{
var CHROME_CHECK_TIME = 2000; // the only way to detect this in Chrome is to wait a bit and see if the window is present
function _is_popup_blocked(popup)
{
return !popup.innerHeight;
}
if (popup_window) {
if (popup_window.closed) {
// opened OK but was closed before we checked
cb(false);
return;
}
if (/chrome/.test(navigator.userAgent.toLowerCase())) {
// wait a bit before testing the popup in chrome
setTimeout(function() {
cb(_is_popup_blocked(popup_window));
}, CHROME_CHECK_TIME);
} else {
// for other browsers, add an onload event and check after that
popup_window.onload = function() {
cb(_is_popup_blocked(popup_window));
};
}
} else {
cb(true);
}
};
答案 11 :(得分:2)
Promise
方法怎么样?
const openPopUp = (...args) => new Promise(s => {
const win = window.open(...args)
if (!win || win.closed) return s()
setTimeout(() => (win.innerHeight > 0 && !win.closed) ? s(win) : s(), 200)
})
您可以像经典的window.open
const win = await openPopUp('popuptest.htm', 'popuptest')
if (!win) {
// popup closed or blocked, handle alternative case
}
您可以更改代码,使其不履行承诺,而不是返回undefined
,我只是想在这种情况下,if
比try / catch
更容易控制流。
答案 12 :(得分:1)
现在,你真的不需要问一个问题“我的主动弹出窗口被阻止了吗?”,因为答案总是“是” - 所有主流浏览器都默认打开弹出窗口阻止程序。最好的方法是只对window.open()进行响应直接点击,这几乎总是允许的。
答案 13 :(得分:1)
HI
我稍微修改了上述解决方案,并认为它至少适用于Chrome。 我的解决方案是在主页打开时检测弹出窗口是否被阻止,而不是在打开弹出窗口时阻止弹出窗口,但我确信有些人可以修改它。:-) 这里的缺点是,当没有弹出窗口阻止程序时,弹出窗口会显示几秒钟(可能会缩短一点)。
我把它放在我的'主'窗口的部分
<script type="text/JavaScript" language="JavaScript">
var mine = window.open('popuptest.htm','popuptest','width=1px,height=1px,left=0,top=0,scrollbars=no');
if(!mine|| mine.closed || typeof mine.closed=='undefined')
{
popUpsBlocked = true
alert('Popup blocker detected ');
if(mine)
mine.close();
}
else
{
popUpsBlocked = false
var cookieCheckTimer = null;
cookieCheckTimer = setTimeout('testPopup();', 3500);
}
function testPopup()
{
if(mine)
{
if(mine.test())
{
popUpsBlocked = false;
}
else
{
alert('Popup blocker detected ');
popUpsBlocked = true;
}
mine.close();
}
}
</script>
popuptest看起来像这样:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head>
<title>Popup test</title>
<script type="text/javascript" language="Javascript">
function test() {if(window.innerHeight!=0){return true;} else return false;}
</script>
</head>
<body>
</body>
</html>
当我在3500毫秒后调出弹出页面上的测试功能时,Chrome已正确设置了内部高度。
我使用变量popUpsBlocked来知道弹出窗口是否在其他javascripts中显示。 即
function ShowConfirmationMessage()
{
if(popUpsBlocked)
{
alert('Popups are blocked, can not display confirmation popup. A mail will be sent with the confirmation.');
}
else
{
displayConfirmationPopup();
}
mailConfirmation();
}
答案 14 :(得分:1)
function openPopUpWindow(format)
{
var win = window.open('popupShow.html',
'ReportViewer',
'width=920px,height=720px,left=50px,top=20px,location=no,directories=no,status=no,menubar=no,toolbar=no,resizable=1,maximize:yes,scrollbars=0');
if (win == null || typeof(win) == "undefined" || (win == null && win.outerWidth == 0) || (win != null && win.outerHeight == 0) || win.test == "undefined")
{
alert("The popup was blocked. You must allow popups to use this site.");
}
else if (win)
{
win.onload = function()
{
if (win.screenX === 0) {
alert("The popup was blocked. You must allow popups to use this site.");
win.close();
}
};
}
}
答案 15 :(得分:0)
据我所知(从我测试过的内容),Chrome会返回一个位置为“about:blank”的窗口对象。 因此,以下内容适用于所有浏览器:
var newWin = window.open(url);
if(!newWin || newWin.closed || typeof newWin.closed=='undefined' || newWin.location=='about:blank')
{
//POPUP BLOCKED
}