Виявити заблоковані спливаючі вікна в Chrome


103

Мені відомі методи JavaScript, щоб визначити, чи блокується спливаюче вікно в інших браузерах (як описано у відповіді на це запитання ). Ось основний тест:

var newWin = window.open(url);

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

Але це не працює в Chrome. До блоку "POPUP BLOCKED" ніколи не дістається, коли спливаюче вікно заблоковано.

Звичайно, тест працює в тій мірі, оскільки Chrome насправді не блокує спливаюче вікно, а відкриває його у крихітному мінімізованому вікні в правому нижньому куті, де відображаються «заблоковані» спливаючі вікна.

Що я хотів би зробити, - це зможе сказати, чи спливаюче блокатор Chrome було заблоковано. Я намагаюся уникати нюху браузера на користь виявлення функцій. Чи можна це зробити без нюху браузера?

Edit : я зараз намагався використовувати роблячи з newWin.outerHeight, newWin.leftі інших аналогічних властивостей для досягнення цієї мети . Google Chrome повертає всі значення положення та висоти як 0, коли спливаюче вікно заблоковано.

На жаль, він також повертає ті самі значення, навіть якщо спливаюче вікно насправді відкрито невідомий час. Через деякий чарівний період (пару секунд у моєму тестуванні) інформація про місцезнаходження та розмір повертається як правильні значення. Іншими словами, я все ще не ближче до з'ясування цього. Будь-яка допомога буде вдячна.


Yoav, місце розташування показує те саме, незалежно від того, блокується спливаюче вікно чи ні. Хтось ще має відповідь, яка не передбачає змушування користувача чекати 3,5 секунди?

Останні рішення від InvisibleBacon та Andy не працюють у Chrome 10: повідомлення "не вдалося до хрому" з'являється, навіть якщо тестовий спливаючий вікно було успішно відображено Будь-яка ідея?

Я думаю, що нове питання виникне для того, щоб, здається, деякі з цих рішень працювали лише з ранніми версіями Chrome.
Брайан Філд

1
@George Bailey Я згоден, але для того, щоб зрозуміти, деякі з них працюють у поточній версії Chrome (19). Первісна ідея Ендрю щодо використання externalHeight (або screenX, як це запропонували інші) для мене добре працює в поєднанні з підходом setTimeout. Але, так, намагання зрозуміти всі ці відповіді було справді заплутаним, поки я не зробив власне тестування.
регулярниймійк

Відповіді:


66

Що ж, "чарівний час", про який ви говорите, - це, ймовірно, коли DOM вискакувача завантажений. Або ж це може бути, коли все (зображення, підвісні CSS тощо) було завантажено. Ви можете це легко перевірити, додавши до спливаючого вікна дуже велику графіку (спочатку очистіть кеш!). Якщо ви використовували Javascript Framework на зразок jQuery (або щось подібне), ви можете використовувати подію Ready () (або щось подібне), щоб зачекати, поки DOM завантажиться, перш ніж перевірити зміщення вікна. Небезпека в цьому полягає в тому, що виявлення 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 секунд для завантаження. У дочірньому вікні потрібно додати тестову функцію:

тест функції () {}

Детектор блокування спливаючих вікон перевіряє, чи існує функція "тест" як член дочірнього вікна.

ДОБАВЛЕНО 15 червня 2015 року:

Я думаю, що сучасним способом вирішити це було б використовувати window.postMessage (), щоб дитина повідомляла батьків про те, що вікно було завантажено. Підхід схожий (дитина каже батькові, що він завантажений), але засоби спілкування покращилися. Я зміг зробити цей крос-домен від дитини:

$(window).load(function() {
  this.opener.postMessage({'loaded': true}, "*");
  this.close();
});

Батько слухає це повідомлення, використовуючи:

$(window).on('message', function(event) {     
  alert(event.originalEvent.data.loaded)
}); 

Сподіваюся, це допомагає.


Багатий, ви - гуру спливаючих програм Javascript. Дякую. Це саме те, що мені було потрібно.
Ендрю Енслі

4
Будь-які оновлення щодо цього? Мабуть, більше не працює ... Конкретно в Chrome
Chris Wagner

Думаю, я знайшов спосіб зробити цю роботу для нових версій Chrome. Дивіться мою відповідь для деталей.
InvisibleBacon

2
В основному в Chrome є помилка. Хоча він приховує спливаюче вікно, воно все одно виконується, і ви все одно повертаєте об'єкт вікна назад, тому регулярні перевірки не працюють. Ось рішення, яке працювало для мене: var popup = window.open (url); if (popup) {popup.onload = function () {console.log (popup.innerHeight> 0? 'open': 'заблоковано'); }} else {console.log ('заблоковано'); } Робочий приклад тут: jsbin.com/uticev/3
Ремі Шарп

1
Ця відповідь більше не є правильною. Будь ласка, змініть її на відповідь @Predrag Stojadinović
Лукас Б

16

Лише одне вдосконалення фрагмента InvisibleBacon (перевірено в 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);
    };
}

Навіщо закривати вікно, якщо спливаючі вікна дозволені? Чи не було б це закриттям спливаючого вікна, яке ви хотіли відкрити?
elemjay19

3
Використовуючи jQuery, замість onload, я б зробив $ (myPopup) .ready (). Запуск локально мій IE був надто швидким, і "перевантаження" вже відбулося.
Метт Конноллі

12

Далі наведено рішення 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);

Сподіваюся, це допомагає! :)


Це справді корисно. Дякую, що поділились.
Сувенду Шехар Гірі

Ласкаво просимо, Сувенду, я радий, що ти знайшов це корисним! Щасливого кодування! :)
Кевін Б

1
Я налаштував цей код, щоб перейти в / навколо URL, який намагається відкрити. Це дозволяє методу _displayError () відображати попередження (я використовую toastr), сповіщаючи користувача про наявність проблеми та надаючи посилання, яке можна натиснути, що обійде більшість блокаторів, оскільки це пряме посилання. Дякую, що поділились!!
Тайлер Форсайт

@TylerForsyщо маєте більше інформації про своє рішення? Будемо в змозі надати прямий посилання на вміст, який можна легко натискати.
Танець Джошуа

1
@JoshuaDance Ось я лише створив суть, щоб продемонструвати свій модифікований код та те, як я його викликаю. Сподіваюся, це допомагає! gist.github.com/tylerforsythe/452ceaad62f507d7cb7bd7ddbffe650c
Tyler Forsythe

10

Відповідь Річа більше не працюватиме для Chrome. Схоже, Chrome зараз реально виконує будь-який JavaScript у спливаючому вікні. Я закінчив перевірку наявності значення screenX 0, щоб перевірити наявність заблокованих спливаючих вікон. Я також думаю, що я знайшов спосіб гарантувати, що ця власність остаточна, перш ніж перевірити. Це працює лише для спливаючих вікон у вашому домені, але ви можете додати обробник завантаження таким чином:

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);
    };
}

Як багато хто повідомляв, властивість "screenX" іноді повідомляє не нульове значення для невдалих спливаючих вікон, навіть після завантаження. Я також відчував таку поведінку, але якщо ви додасте перевірку після нульового тайм-аут мс, властивість screenX завжди видає послідовне значення.

Повідомте мене, чи є способи зробити цей сценарій більш надійним. Здається, працює для моїх цілей.


Це не для мене, onloadніколи не стріляє.
листопад

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();
    }

ExternalHeight та externalWidth призначені для хромування, оскільки фокус "about: blank" зверху вже не працює в хромі.


1
Хороший улов про зміни хрому та дякую за оновлення тут. Ваша відповідь має бути позначена як правильна.
Лукас Б

Зовнішня ширина та externalHeight більше не працюють у Chrome
Роман

5

Я збираюся просто скопіювати / вставити відповідь, надану тут: https://stackoverflow.com/a/27725432/892099 від DanielB. працює на chrome 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.");
  }
}

3

Як щодо 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для цього випадку.


Це працює для виявлення рекламних блоків розширень хрому. +1
Micheal C Wallas

2

Перевірте положення вікна щодо батьківського. Chrome робить це вікно майже поза екраном.


Я спробую це і дам вам знати мої результати. Дякую.
Ендрю Енслі

Google Chrome повідомляє про ліве та верхнє зміщення як 0, коли спливаюче вікно "заблоковано". Я думав, це мій золотий квиток, але ні. Він повідомляє про компенсації як 0 відразу після фактичного відкриття. У якийсь чарівний момент у майбутньому після відкриття верхній і лівий зміщення повідомляються правильно.
Ендрю Енслі

Перевірте мій пост на спосіб, який, здається, гарантує, що компенсації встановлені до перевірки.
InvisibleBacon

2

У мене була схожа проблема із тим, що спливаючі вікна не відкривалися в Chrome. Мене було розчаровано, тому що я не намагався зробити щось підлий, як спливаюче завантаження, просто відкриваючи вікно, коли користувач натискав. Я був дуже розчарований, оскільки запуск моєї функції, яка включала window.open () з командного рядка firebug, працював, а фактично натискання на моє посилання не робило! Ось моє рішення:

Неправильний спосіб: запустіть window.open () від слухача подій (у моєму випадку dojo.connect до методу події onclick у вузлі DOM).

dojo.connect(myNode, "onclick", function() {
    window.open();
}

Правильний шлях: призначення функції властивості onclick вузла, який називається window.open ().

myNode.onclick = function() {
    window.open();
}

І, звичайно, я все ще можу зробити слухачів подій для тієї самої події onclick, якщо мені потрібно. З цією зміною я міг би відкрити свої вікна, навіть якщо для Chrome встановлено значення "Не дозволяти жодному сайту показувати спливаючі вікна". Радість.

Якщо хтось розумний у способах Chrome, може сказати решті з нас, чому це має значення, я хотів би почути це, хоча я підозрюю, що це лише спроба закрити двері для шкідливих програмних спливаючих вікон.


Дякуємо, що поділилися своїм рішенням. Це працює. Це найкращий і найчистіший спосіб відкрити спливаючі вікна в хромі. Ваша відповідь має бути зверху. Решта рішень - це просто "брудні" хаки.
Mandeep Janjua

2

Ось версія, яка зараз працює в Chrome. Лише невелике внесення змін до рішення Річа, хоча я додав у обгортку, яка теж обробляє час.

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 секунд має бути цілком безпечним).


2

Цей фрагмент містить у собі все вищезазначене - Чомусь StackOverflow виключає першу та останню рядки коду з кодового блоку нижче, тому я написав блог на ньому. Для повного пояснення та решти (завантажуваного) коду перегляньте мій блог на сайті codecodeabode.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();

2

Нічого, звичайно, тут багато рішень. Це моє, він використовує рішення, взяті з поточної прийнятої відповіді (яка не працює в останньому Chrome і вимагає завершити її в тайм-аут), а також відповідне рішення для цієї теми (що насправді ванільна JS, а не jQuery) .

Шахта використовує архітектуру зворотного виклику, яка буде надіслана, 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);
    }
};

1

Відповідь Джейсона - єдиний метод, про який я теж можу подумати, але покладаючись на таке положення, це трохи хитрощі!

У ці дні вам не потрібно ставити запитання "чи було заблоковано моє незатребуване спливаюче вікно?", Оскільки відповідь незмінно "так" - усі основні браузери за замовчуванням увімкнено блокування спливаючих вікон. Найкращим підходом є тільки window.open () у відповідь на прямий клацання, що майже завжди дозволено.


2
Я знаю кращі практики тощо. Але я знаходжусь у ситуації, коли мені потрібно виконати це завдання. Ось чому я задав це питання, а не "чи слід?"
Ендрю Енслі

1

ПРИВІТ

Я трохи змінив описані вище рішення і думаю, що він працює принаймні для 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>

Спливаючий тест виглядає так:

<!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();
}

Це, на жаль, передбачає, що та сторінка, яку ви намагаєтеся спливати, контролюється нами. Мені потрібно відкрити зовнішню сторінку, над якою я не маю ніякого контролю.
Роман

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();
            } 
        };
    }
}

0

Наскільки я можу сказати (з того, що я перевірив) Chrome повертає об’єкт вікна з розташуванням "about: blank". Отже, для всіх браузерів має працювати наступне:

var newWin = window.open(url);
if(!newWin || newWin.closed || typeof newWin.closed=='undefined' || newWin.location=='about:blank')
{
    //POPUP BLOCKED
}

розташування все ще буде "приблизно: порожнім", навіть для спливаючих вікон, які не заблоковані. Я протестував на Chrome v28.0.1500.72
Роман
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.