Detectar pop-up bloqueado no Chrome


103

Estou ciente das técnicas de javascript para detectar se um pop-up está bloqueado em outros navegadores (conforme descrito na resposta a esta pergunta ). Aqui está o teste básico:

var newWin = window.open(url);

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

Mas isso não funciona no Chrome. A seção "POPUP BLOCKED" nunca é alcançada quando o popup é bloqueado.

Claro, o teste está funcionando até certo ponto, já que o Chrome não bloqueia o pop-up, mas o abre em uma pequena janela minimizada no canto inferior direito que lista os pop-ups "bloqueados".

O que eu gostaria de fazer é saber se o popup foi bloqueado pelo bloqueador de popup do Chrome. Tento evitar o farejamento do navegador em favor da detecção de recursos. Existe uma maneira de fazer isso sem farejar o navegador?

Editar : Eu já tentei fazer uso de newWin.outerHeight, newWin.lefte outras propriedades semelhantes para alcançar este objetivo. O Google Chrome retorna todos os valores de posição e altura como 0 quando o pop-up é bloqueado.

Infelizmente, ele também retorna os mesmos valores, mesmo se o pop-up for realmente aberto por um período de tempo desconhecido. Após algum período mágico (alguns segundos no meu teste), as informações de localização e tamanho são retornadas como os valores corretos. Em outras palavras, ainda não estou mais perto de descobrir isso. Qualquer ajuda seria apreciada.


Yoav, o local mostra o mesmo independentemente de o pop-up estar bloqueado ou não. Alguém mais tem uma resposta que não envolva fazer o usuário esperar 3,5 segundos?

As soluções mais recentes de InvisibleBacon e Andy não funcionam no Chrome 10: a mensagem "falhou para o cromo" aparece mesmo se o pop-up de teste foi exibido com sucesso. Qualquer ideia?

Eu acho que uma nova questão seria apropriada, já que algumas dessas soluções parecem ter funcionado apenas com as primeiras versões do Chrome.
— Bryan Field

1
@George Bailey Eu concordo, mas só para ficar claro, alguns deles funcionam na versão atual do Chrome (19). A ideia original de Andrew de usar outerHeight (ou screenX, como outros sugeriram) está funcionando bem para mim, combinada com a abordagem setTimeout. Mas, sim, tentar entender todas essas respostas era realmente confuso até que fiz meu próprio teste.
— regular de

Respostas:


66

Bem, o "momento mágico" de que você fala é provavelmente quando o DOM do pop-up foi carregado. Ou então pode ser quando tudo (imagens, CSS externo, etc.) tiver sido carregado. Você pode testar isso facilmente adicionando um gráfico muito grande ao pop-up (limpe o cache primeiro!). Se você estava usando um Javascript Framework como jQuery (ou algo semelhante), você poderia usar o evento ready () (ou algo semelhante) para esperar o DOM carregar antes de verificar o deslocamento da janela. O perigo disso é que a detecção do Safari funciona de forma conflitante: o DOM do pop-up nunca estará pronto () no Safari porque ele fornecerá um identificador válido para a janela que você está tentando abrir - se ela realmente abre ou não. (na verdade, acredito que o código de teste pop-up acima não funcionará no Safari.)

Acho que a melhor coisa que você pode fazer é envolver seu teste em um setTimeout () e dar ao pop-up 3-5 segundos para completar o carregamento antes de executar o teste. Não é perfeito, mas deve funcionar pelo menos 95% do tempo.

Aqui está o código que uso para detecção de navegadores cruzados, sem a parte do 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;
}

O que faço é executar este teste do pai e envolvê-lo em um setTimeout (), dando à janela filho 3-5 segundos para carregar. Na janela filha, você precisa adicionar uma função de teste:

teste de funcionamento() {}

O detector do bloqueador de pop-up testa para ver se a função "teste" existe como um membro da janela filho.

ADICIONADO EM 15 DE JUNHO DE 2015:

Acho que a maneira moderna de lidar com isso seria usar window.postMessage () para que a criança notifique o pai de que a janela foi carregada. A abordagem é semelhante (a criança diz aos pais que está carregada), mas os meios de comunicação melhoraram. Consegui fazer este cross-domain desde a criança:

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

O pai ouve esta mensagem usando:

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

Espero que isto ajude.


Rico, você é um guru do pop-up de javascript. Obrigado. Isso é exatamente o que eu precisava.
— Andrew Ensley,

4
Alguma atualização sobre isso? Parece não funcionar mais ... Especificamente no Chrome
— Chris Wagner,

Acho que encontrei uma maneira de fazer isso funcionar para novas versões do Chrome. Veja minha resposta para detalhes.
— InvisibleBacon

2
Basicamente, há um bug no Chrome. Embora oculte o pop-up, ele ainda executa e você ainda recebe o objeto janela de volta - portanto, as verificações regulares não funcionam. Aqui está a solução que funcionou para mim: var popup = window.open (url); if (popup) {popup.onload = function () {console.log (popup.innerHeight> 0? 'aberto': 'bloqueado'); }} else {console.log ('bloqueado'); } Exemplo de trabalho aqui: jsbin.com/uticev/3
— Remy Sharp

1
Esta resposta não está mais correta, altere-a para a resposta de @Predrag Stojadinović
— Lucas B

16

Apenas uma melhoria no snipet do InvisibleBacon (testado no IE9, Safari 5, Chrome 9 e 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);
    };
}

Por que fechar a janela se pop-ups são permitidos? isso não fecharia o pop-up que você queria abrir em primeiro lugar?
— elemjay19

3
Usando jQuery, em vez de onload, eu faria $ (myPopup) .ready (). Rodando localmente, meu IE era muito rápido e "onload" já havia ocorrido.
— Matt Connolly

12

A seguir está uma solução jQuery para verificação de bloqueador de pop-up. Ele foi testado em FF (v11), Safari (v6), Chrome (v23.0.127.95) e IE (v7 e v9). Atualize a função _displayError para lidar com a mensagem de erro conforme achar necessário.

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

Uso:

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

Espero que isto ajude! :)


Isso é realmente útil. Obrigado por compartilhar.
— Suvendu Shekhar Giri

Seja bem-vindo, Suvendu, fico feliz que você tenha achado isso útil! Boa codificação! :)
— Kevin B

1
Eu ajustei este código para passar dentro / ao redor da url que está tentando ser aberta. Isso permite que o método _displayError () exiba um alerta (estou usando toastr) notificando o usuário de que há um problema e forneça um link clicável que contornará a maioria dos bloqueadores, pois é um link direto. Obrigado por compartilhar !!
— Tyler Forsythe

@TylerForsythe você tem mais informações sobre sua solução? Adoraria ser capaz de fornecer um link clicável diretamente para o conteúdo.
— Joshua Dance

1
@JoshuaDance Aqui está uma essência que acabei de criar para demonstrar meu código modificado e como o invoco. Espero que ajude! gist.github.com/tylerforsythe/452ceaad62f507d7cb7bd7ddbffe650c
— Tyler Forsythe

10

A resposta de Rich não vai funcionar mais para o Chrome. Parece que o Chrome realmente executa qualquer Javascript na janela pop-up agora. Acabei verificando se há um valor de screenX de 0 para verificar se há pop-ups bloqueados. Também acho que encontrei uma maneira de garantir que esta propriedade seja definitiva antes de verificar. Isso só funciona para pop-ups em seu domínio, mas você pode adicionar um gerenciador onload como este:

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

Como muitos relataram, a propriedade "screenX" às vezes relata diferente de zero para pop-ups com falha, mesmo após onload. Eu também experimentei esse comportamento, mas se você adicionar a verificação após um tempo limite de zero ms, a propriedade screenX sempre parece gerar um valor consistente.

Deixe-me saber se há maneiras de tornar este script mais robusto. Parece funcionar para meus propósitos.


Não para mim, onloadnunca dispara.
— folha de

9

Isso funcionou para mim:

    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 e outerWidth são para cromo porque o truque 'about: blank' acima não funciona mais no cromo.


1
Bom entendimento sobre as mudanças do cromo e obrigado por atualizá-lo aqui. Sua resposta deve ser marcada como correta.
— Lucas B

O outerWidth e o outerHeight também não funcionam mais no Chrome
— Romano

5

Vou apenas copiar / colar a resposta fornecida aqui: https://stackoverflow.com/a/27725432/892099 de DanielB. funciona no Chrome 40 e é muito limpo. nenhum hacks sujo ou envolve espera.

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

Que tal uma Promiseabordagem?

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

E você pode usá-lo como o clássico window.open

const win = await openPopUp('popuptest.htm', 'popuptest')
if (!win) {
  // popup closed or blocked, handle alternative case
}

Você poderia alterar o código para que ele falhasse a promessa em vez de retornar undefined, apenas pensei que ifera um fluxo de controle mais fácil do que try / catchneste caso.


Isso funciona para detectar adblockers de extensão do Chrome. +1
— Micheal C Wallas

2

Verifique a posição da janela em relação ao pai. O Chrome faz a janela parecer quase fora da tela.


Vou tentar fazer isso e deixar você saber meus resultados. Obrigado.
— Andrew Ensley

O Google Chrome relata os deslocamentos esquerdo e superior como 0 quando o pop-up é "bloqueado". Achei que esse fosse meu bilhete dourado, mas não. Ele relata os deslocamentos como 0 imediatamente após a abertura também. Em algum ponto mágico no futuro após a abertura, os deslocamentos superior e esquerdo são relatados corretamente.
— Andrew Ensley,

Verifique meu post para uma maneira que parece garantir que os offsets estão definidos antes de verificar.
— InvisibleBacon

2

Eu tive um problema semelhante com pop-ups não abrindo no Chrome. Fiquei frustrado porque não estava tentando fazer algo sorrateiro, como um pop-up onload, apenas abrindo uma janela quando o usuário clicou. Eu estava DUVIDAMENTE frustrado porque executar minha função que incluía o window.open () da linha de comando do firebug funcionou, enquanto clicar no meu link não funcionou! Aqui estava minha solução:

Maneira errada: executando window.open () de um ouvinte de evento (no meu caso, dojo.connect para o método de evento onclick de um nó DOM).

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

Caminho certo: atribuindo uma função à propriedade onclick do nó que chamou window.open ().

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

E, é claro, ainda posso fazer ouvintes de evento para o mesmo evento onclick, se necessário. Com essa mudança, eu poderia abrir minhas janelas mesmo que o Chrome estivesse configurado para "Não permitir que nenhum site mostre pop-ups". Alegria.

Se alguém conhecedor do Chrome puder dizer ao restante de nós por que ele faz a diferença, adoraria ouvir, embora suspeite que seja apenas uma tentativa de fechar a porta para popups programáticos maliciosos.


Obrigado por compartilhar sua solução. Funciona. Esta é a maneira melhor e mais limpa de abrir pop-ups cromados. Sua resposta deve estar no topo. O resto das soluções são apenas hacks "sujos".
— Mandeep Janjua

2

Esta é uma versão que está funcionando atualmente no Chrome. Apenas uma pequena alteração da solução de Rich, embora eu tenha adicionado um invólucro que controla o tempo também.

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

Para usá-lo, faça o seguinte:

var popup=window.open('location',etc...);
checkPopupBlocked(popup);

Se o pop-up for bloqueado, a mensagem de alerta será exibida após o período de cortesia de 5 segundos (você pode ajustar isso, mas 5 segundos deve ser bastante seguro).


2

Este fragmento incorpora todos os itens acima - por algum motivo - StackOverflow está excluindo a primeira e a última linha do código no bloco de código abaixo, então escrevi um blog sobre ele. Para obter uma explicação completa e o restante do código (para download), dê uma olhada em meu blog em 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();

2

Uau, com certeza existem muitas soluções aqui. Este é o meu, ele usa soluções retiradas da resposta aceita atual (que não funciona no Chrome mais recente e requer envolvê-la em um tempo limite), bem como uma solução relacionada neste tópico (que é na verdade JS vanilla, não jQuery) .

O meu usa uma arquitetura de retorno de chamada que será enviada truequando o pop-up for bloqueado e falsecaso contrário.

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

A resposta de Jason é o único método que consigo pensar também, mas confiar em uma posição como essa é um pouco duvidoso!

Atualmente, você realmente não precisa fazer a pergunta “meu popup não solicitado foi bloqueado?”, Porque a resposta é invariavelmente “sim” - todos os principais navegadores têm o bloqueador de popup ativado por padrão. A melhor abordagem é apenas window.open () em resposta a um clique direto, que quase sempre é permitido.


2
Eu conheço as melhores práticas, etc. Mas estou em uma situação em que preciso realizar essa tarefa. É por isso que fiz esta pergunta e não "deveria?"
— Andrew Ensley,

1

OI

Modifiquei ligeiramente as soluções descritas acima e acho que está funcionando pelo menos para o Chrome. Minha solução é detectar se o pop-up está bloqueado quando a página principal é aberta, não quando o pop-up é aberto, mas tenho certeza que há algumas pessoas que podem modificá-lo. :-) A desvantagem aqui é que a janela pop-up é exibida por alguns segundos (pode ser possível encurtar um pouco) quando não há bloqueador de pop-up.

Eu coloquei isso na seção da minha janela 'principal'

<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>

O popuptest se parece com isto:

<!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>

Como eu chamo a função de teste na página pop-up após 3500 ms, a altura interna foi configurada corretamente pelo Chrome.

Eu uso a variável popUpsBlocked para saber se os pop-ups são exibidos ou não em outros javascripts. ie

function ShowConfirmationMessage()
{
if(popUpsBlocked)
 { 
  alert('Popups are blocked, can not display confirmation popup. A mail will be sent with the confirmation.');
 } 
 else
 { 
  displayConfirmationPopup();
 }
 mailConfirmation();
}

Infelizmente, isso pressupõe que a página que você está tentando abrir é controlada por nós. Preciso abrir uma página externa sobre a qual não tenho controle.
— Romano

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

Até onde eu posso dizer (pelo que testei), o Chrome retorna um objeto de janela com localização de 'sobre: ​​em branco'. Portanto, o seguinte deve funcionar para todos os navegadores:

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

o local ainda será "about: blank" mesmo para pop-up que não esteja bloqueado. Testei no Chrome v28.0.1500.72
— Romano de
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.