Jak mogę wykryć, czy przeglądarka blokuje wyskakujące okienko?

132

Od czasu do czasu natknąłem się na stronę internetową, która próbuje otworzyć nowe okno (w celu wprowadzenia danych przez użytkownika lub czegoś ważnego), ale blokada wyskakujących okienek zapobiega temu.

Jakich metod może użyć wywołujące okno, aby upewnić się, że nowe okno zostało uruchomione poprawnie?

Nathan Bedford
źródło

Odpowiedzi:

165

Jeśli używasz JavaScript do otwierania wyskakującego okienka, możesz użyć czegoś takiego:

var newWin = window.open(url);             

if(!newWin || newWin.closed || typeof newWin.closed=='undefined') 
{ 
    //POPUP BLOCKED
}
omar
źródło
Oto odpowiedź dla Chrome: Detect-
Blocked
@ajwaka, czy mógłbyś uprzejmie wyjaśnić, czy ta odpowiedź nie działa w przypadku Chrome, czy jest powód, dla którego druga odpowiedź jest lepsza w przypadku Chrome? dzięki!
Crashalot
1
@ajwaka przynajmniej dziś ten kod wydaje się działać na chrome, stąd pytanie.
Crashalot
@Crashalot - Pytasz mnie o coś, na co odpowiedziałem 6 lat temu - niestety już nie pamiętam sytuacji, a przeglądarki przeszły długą drogę w ciągu 6 lat.
ajwaka
43

Wypróbowałem kilka powyższych przykładów, ale nie mogłem zmusić ich do pracy z Chrome. Wydaje się, że to proste podejście działa w Chrome 39, Firefox 34, Safari 5.1.7 i IE 11. Oto fragment kodu z naszej biblioteki JS.

openPopUp: function(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.");
    }
}
DanielB
źródło
1
@Surendra, czy możesz określić, co masz na myśli, mówiąc „nie działa”? Błąd w czasie analizy? Błąd w czasie wykonywania? Wyskakujące okienko otwiera się, ale jest oznaczone jako zablokowane? Wyskakujące okienko jest zablokowane, ale jest oznaczone jako otwarte? Nie widzę żadnego powodu, dla którego eksplorator miałby to zawieść, chyba że wywołanie funkcji focus () na NULL jest dozwolone w takim przypadku, test na NULL przed próbą po prostu zadziała.
FrancescoMM
IE zawsze zwraca null, nawet jeśli wyskakujące okienko zakończyło się pomyślnie.
Devin Garner
34

Aktualizacja: Popupy istnieją od naprawdę starożytnych czasów. Początkowym pomysłem było pokazanie innej treści bez zamykania głównego okna. Obecnie istnieją inne sposoby, aby to zrobić: JavaScript może wysyłać żądania do serwera, więc wyskakujące okienka są rzadko używane. Ale czasami są nadal przydatne.

W przeszłości złe strony często nadużywały wyskakujących okienek. Zła strona może otwierać mnóstwo wyskakujących okienek z reklamami. Dlatego teraz większość przeglądarek próbuje blokować wyskakujące okienka i chronić użytkownika.

Większość przeglądarek blokuje wyskakujące okienka, jeśli są wywoływane poza programami obsługi zdarzeń wyzwalanymi przez użytkownika, takimi jak onclick.

Jeśli się nad tym zastanowić, to trochę skomplikowane. Jeśli kod znajduje się bezpośrednio w module obsługi onclick, to jest to łatwe. Ale co otwiera wyskakujące okienko w setTimeout?

Wypróbuj ten kod:

 // open after 3 seconds
setTimeout(() => window.open('http://google.com'), 3000);

Wyskakujące okienko otwiera się w przeglądarce Chrome, ale jest blokowane w przeglądarce Firefox.

… Działa to również w Firefoksie:

 // open after 1 seconds
setTimeout(() => window.open('http://google.com'), 1000);

Różnica polega na tym, że Firefox traktuje limit czasu 2000 ms lub mniejszy jest akceptowalny, ale po nim - usuwa „zaufanie”, zakładając, że teraz jest ono „poza akcją użytkownika”. Więc pierwszy jest zablokowany, a drugi nie.


Oryginalna odpowiedź, aktualna w 2012 roku:

To rozwiązanie do sprawdzania blokowania wyskakujących okienek zostało przetestowane w FF (v11), Safari (v6), Chrome (v23.0.127.95) i IE (v7 i v9). Zaktualizuj funkcję displayError, aby obsłużyć komunikat o błędzie według własnego uznania.

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

Stosowanie:

var popup = window.open("http://www.google.ca", '_blank');
popupBlockerChecker.check(popup);

Mam nadzieję że to pomoże! :)

Kevin B.
źródło
20
Myślę, że potrzebujesz więcej podkreśleń
Jacob Stamm,
W przeglądarce Firefox powoduje to wyświetlenie pustej strony i nie można nawet zobaczyć komunikatu blokującego wyskakujące okienka na stronie otwieracza. Jak zamknąć pustą stronę?
user460114
Zwróć uwagę, że jeśli adres URL wyskakującego okienka jest plikiem do pobrania (który znajduje się Content-Disposition: attachment;w nagłówku odpowiedzi), wyskakujące okienko zostanie natychmiast zamknięte, dlatego setTimeoutkod nie powiedzie się, a przeglądarka będzie narzekać, że „Blokowanie wyskakujących okienek jest włączone!”. W przypadku Chrome polecam rozwiązanie @ DanielB i działa świetnie.
wonsuc
1
@wonsuc podczas otwierania linku, który ma Content-Disposition: attachment;nagłówek, nie musisz otwierać go w wyskakującym okienku. Po prostu umieść bezpośredni link do zasobu, który chcesz pobrać, a natywne zachowanie przeglądarki pozwoli na pobranie bez przekierowywania Cię z bieżącej strony.
Kevin B
@KevinB Muszę powiedzieć, że jestem w określonej sytuacji. Muszę pobrać wiele plików, które generują pliki PDF z HTML. A jeśli zawartość HTML jest duża, czasami zajmuje to kilka sekund, a jeśli go używam window.location, jeśli wygenerowanie pierwszego pliku trwa zbyt długo, zostanie zignorowany, gdy rozpocznie się drugie żądanie. To jest powód, dla którego muszę używać window.open, ponieważ window.locationnigdy nie informuje mnie, kiedy kończy się odpowiedź.
wonsuc
13

Jednym z „rozwiązań”, które zawsze będzie działać niezależnie od firmy lub wersji przeglądarki, jest po prostu umieszczenie komunikatu ostrzegawczego na ekranie, gdzieś blisko elementu sterującego, który utworzy wyskakujące okienko, które uprzejmie ostrzega użytkownika, że ​​działanie wymaga wyskakującego okienka up i proszę je włączyć na stronie.

Wiem, że to nie jest wyszukane ani nic takiego, ale nie może być prostsze i wymaga tylko około 5 minut testowania, a potem możesz przejść do innych koszmarów.

Gdy użytkownik zezwoli na wyświetlanie wyskakujących okienek w Twojej witrynie, rozważ również, czy nie przesadzasz z wyskakującymi okienkami. Ostatnią rzeczą, którą chcesz robić, jest drażnienie odwiedzających.

UncaAlby
źródło
1
Niestety, czasami wszystkie inne rozwiązania w tym pytaniu są nie do przyjęcia - tylko to. Czemu? Ponieważ wszyscy próbują wyświetlić wyskakujące okienko - a nie tylko wykryć, czy wyskakujące okienka są włączone. A jeśli chcę to zrobić po cichu?
Sagi Mann
Coś do zapamiętania to również to, że użytkownik nie zawsze może po prostu włączyć wyskakujące okienka dla Twojej witryny. Na przykład w starszych wersjach Safari użytkownik może tylko włączyć lub całkowicie wyłączyć blokowanie wyskakujących okienek, a biała lista nie jest dostępna.
Jeremy
1

Połączyłem rozwiązania @Kevin B i @ DanielB.
To jest dużo prostsze.

var isPopupBlockerActivated = function(popupWindow) {
    if (popupWindow) {
        if (/chrome/.test(navigator.userAgent.toLowerCase())) {
            try {
                popupWindow.focus();
            } catch (e) {
                return true;
            }
        } else {
            popupWindow.onload = function() {
                return (popupWindow.innerHeight > 0) === false;
            };
        }
    } else {
        return true;
    }
    return false;
};

Stosowanie:

var popup = window.open('https://www.google.com', '_blank');
if (isPopupBlockerActivated(popup)) {
    // Do what you want.
}
wonsuc
źródło
1
isPopupBlockerActivated funkcja nigdy nie wraca return (popupWindow.innerHeight > 0) === false;. Funkcja zwraca false, gdy Twoja przeglądarka nie jest Chrome. Ponieważ onload jest procesem asynchronicznym. Twoja funkcja zwraca wartość false, a następnie wykonuje onload, ale wynik nigdy nie zwraca.
Onur Gazioğlu,
0

Wypróbowałem wiele rozwiązań, ale jedynym, które mogłem wymyślić, które działało również z uBlock Origin, było wykorzystanie limitu czasu do sprawdzenia statusu zamkniętego wyskakującego okienka.

function popup (url, width, height) {
    const left = (window.screen.width / 2) - (width / 2)
    const top = (window.screen.height / 2) - (height / 2)
    let opener = window.open(url, '', `menubar=no, toolbar=no, status=no, resizable=yes, scrollbars=yes, width=${width},height=${height},top=${top},left=${left}`)

    window.setTimeout(() => {
        if (!opener || opener.closed || typeof opener.closed === 'undefined') {
            console.log('Not allowed...') // Do something here.
        }
    }, 1000)
}

Oczywiście to hack; jak wszystkie rozwiązania tego problemu.

Musisz zapewnić wystarczająco dużo czasu w swoim setTimeout, aby uwzględnić początkowe otwarcie i zamknięcie, więc nigdy nie będzie dokładnie dokładne. Będzie to pozycja prób i błędów.

Dodaj to do swojej listy prób.

Michael Giovanni Pumo
źródło
0

Prostym podejściem, jeśli posiadasz również kod potomny , byłoby utworzenie prostej zmiennej w jej html, jak poniżej:

    <script>
        var magicNumber = 49;
    </script>

A następnie sprawdź jego istnienie od rodzica, coś podobnego do następującego:

    // Create the window with login URL.
    let openedWindow = window.open(URL_HERE);

    // Check this magic number after some time, if it exists then your window exists
    setTimeout(() => {
        if (openedWindow["magicNumber"] !== 32) {
            console.error("Window open was blocked");
        }
    }, 1500);

Czekamy chwilę, aby upewnić się, że strona została załadowana i sprawdzić, czy istnieje. Oczywiście, gdyby okno nie załadowało się po 1500 ms, zmienna nadal by była undefined.

Lalit Umbarkar
źródło
-1

Korzystając ze zdarzenia onbeforeunload możemy sprawdzić w następujący sposób

    function popup()
    {
        var chk=false;
        var win1=window.open();
        win1.onbeforeunload=()=>{
            var win2=window.open();
            win2.onbeforeunload=()=>{
                chk=true;
            };
        win2.close();
        };
        win1.close();
        return chk;
    }

otworzy 2 czarne okna w tle

funkcja zwraca wartość logiczną.

Yash Bora
źródło