Evita i blocchi popup del browser


172

Sto sviluppando un flusso di autenticazione OAuth esclusivamente in JavaScript e voglio mostrare all'utente la finestra "concedi accesso" in un popup, ma viene bloccato.

Come posso impedire che le finestre pop-up create da entrambi window.openo window.showModalDialogvengano bloccate dai blocchi popup dei diversi browser?


11
Anche se fosse possibile (non lo so), se le persone usano i blocchi popup dovresti rispettarlo. La maggior parte dei browser visualizza un messaggio quando un sito ha tentato di aprire un popup in modo che possano ancora vederlo se lo desiderano. Puoi inserire un'osservazione sul tuo sito che alcuni contenuti si aprono in un popup e l'utente dovrebbe consentirli per procedere.
Felix Kling,

5
La migliore pratica sarebbe simile a: 1) Fallo con successo 2) Chiudi le finestre e scuoti la porta e la paura dalla folla di mecenati sconvolti 3) Pentiti, rimuovi il pop-up-busta-busta e rispetta il tuo pubblico.
Alex Mcp,

Alex e Felix, ho aggiornato la domanda. Non userò la conoscenza per il male :). Grazie!
Pablo Fernandez,

9
Vorrei aggiungere che bypassare un blocco popup potrebbe in realtà provare a migliorare l'esperienza dell'utente. In un esempio su cui sto lavorando ora, stiamo usando un'applicazione Javascript (basata su ExtJS) e stiamo cercando di consentire agli utenti di pagare tramite paypal. Stiamo dando loro un pulsante su cui possono fare clic per avviare paypal in una nuova finestra, ma alcune versioni di IE lo stanno bloccando come popup (anche se si tratta di un pulsante). Se ora attivano il popup, lo schermo viene ricaricato e come app JavaScript, perdiamo lo stato della finestra e devono ricominciare da capo. Quindi davvero: il problema è che IE è stupido.
NateDSaint,

1
@FelixKling Sì, è possibile. I produttori di browser ci hanno già pensato. L'apertura di un popup è OK per quanto riguarda le intenzioni dell'utente (segnalato dall'utente che fa clic su un collegamento o un pulsante). I blocchi popup dovrebbero rispettare le intenzioni dell'utente. Se il blocco popup di IE non funziona, è il blocco popup che è in errore. Gli utenti utilizzano i blocchi popup per impedire agli script di aprire i popup a piacimento, non per bloccare i popup che essi stessi hanno tentato di aprire (facendo clic su un pulsante o un collegamento).
Stijn de Witt,

Risposte:


286

La regola generale è che i blocchi popup si attiveranno se window.openinvocati da javascript o simili non vengono richiamati dall'azione diretta dell'utente . Cioè, puoi chiamare window.openin risposta a un clic sul pulsante senza essere colpito dal blocco dei popup, ma se inserisci lo stesso codice in un evento timer verrà bloccato. Anche la profondità della catena di chiamate è un fattore: alcuni browser più vecchi guardano solo il chiamante immediato, i browser più recenti possono tornare indietro per vedere se il chiamante era un clic del mouse, ecc. Mantenerlo il più basso possibile per evitare i blocchi popup.


2
È interessante notare che i popup avviati attraverso un evento di modifica associato a un elemento select verranno bloccati (in Chrome, non in FF), anche se l'evento viene avviato da un'azione dell'utente diretto, come un clic. Sebbene siano associati a un input, sono consentiti. Strano.
ccnokes,

6
Nessuno ha detto che il browser fosse coerente. : P
dthorpe,

8
Attraverso esperimenti ho capito che la profondità dello stack non ha nulla a che fare con il blocco popup. Controlla effettivamente se window.open viene chiamato entro 1 secondo dall'azione dell'utente o meno. Testato su Chrome 46 e Firefox 42.
Mesqalito,

Il timeout di 1 secondo può essere aggirato in entrambi i browser consentendo una quantità indefinita di tempo usando la risposta di @ tj-crowder in questa pagina .. avere l'URL che stai chiamando tramite ajax essere un po 'php (o qualunque cosa) che utilizza sleep ( ) per un periodo di tempo prima che restituisca una risposta. Il browser si bloccherà mentre "carica" ​​la pagina .. quindi attiva il popup quando riceve una risposta. In Chrome, tuttavia, è necessario aggiungere un avviso () proprio prima di ajax () per far funzionare questo trucco.
fanfara

184

Sulla base di Jason Sebring 's punta molto utile , e sulle cose coperto qua e , ho trovato una soluzione perfetta per il mio caso:

Pseudo codice con frammenti Javascript:

  1. creare immediatamente un popup vuoto sull'azione dell'utente

    var importantStuff = window.open('', '_blank');

    Opzionale: aggiungi un messaggio informativo "in attesa". Esempi:

    a) Una pagina HTML esterna: sostituire la riga sopra con

    var importantStuff = window.open('http://example.com/waiting.html', '_blank');

    b) Testo: aggiungi la seguente riga sotto quella sopra:

    importantStuff.document.write('Loading preview...');
  2. riempilo di contenuto quando è pronto (ad esempio, quando viene restituita la chiamata AJAX)

    importantStuff.location.href = 'http://shrib.com';

Arricchisci la chiamata window.opencon tutte le opzioni aggiuntive di cui hai bisogno.

In realtà utilizzo questa soluzione per un reindirizzamento mailto e funziona su tutti i miei browser (Windows 7, Android). Il _blankbit aiuta il reindirizzamento mailto a funzionare su dispositivi mobili, tra l'altro.

La tua esperienza? Qualche modo per migliorare questo?


1
? quindi cosa fai se non proviene dall'azione dell'utente nel browser? Per il mio esempio, dopo che l'utente si autentica sul server, deve aprire una nuova scheda
Don Cheadle,

@mmcrae non farlo. Qualunque cosa tu voglia fare, c'è un modo migliore di una finestra popup. Altrimenti, è probabile che non vorrei mai vedere il tuo sito. I browser di oggi si assicurano che non dovresti essere in grado di farlo - vedi la risposta di @dthorpe .
Swiss Mister,

5
Whatever it is you intend to do, there is a better way than a popup windowlol? Strana generalizzazione. Il cliente desidera che la pagina in cui è autenticato rimanga aperta e che il nuovo sito / pagina di destinazione dopo l'autenticazione si apra in una nuova scheda. Sì, non la mia idea di eccellente esperienza utente ... ma sembra ragionevole
Don Cheadle,

@mmcrae. Siediti e pensa seriamente. Ti prometto che troverai una "azione dell'utente" nello scenario che descrivi. Il punto centrale della mia risposta è che crei la finestra popup quando hai l'azione dell'utente e poi la riempi di contenuto in un secondo momento. Suggerimento per il tuo caso: l'utente preme "autentica" -> crea il popup (vuoto); il timer è attivo o la risposta del server è tornata o altro -> riempire il contenuto nel popup.
Swiss Mister,

3
Suggerimento utile, se la richiesta Ajax non riesce, chiama importantStuff.closeper chiudere la nuova scheda e fornire e avvisare nella pagina originale.
Oca,

24

Inoltre, Swiss Mister Post, nel mio caso il window.open è stato lanciato all'interno di una promessa, che ha attivato il blocco dei popup, la mia soluzione era: in angolare:

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

è così che puoi aprire una nuova scheda usando la risposta promessa e non invocare il blocco popup.


1
Questo ha portato alla mia soluzione! Dove ho creato una variabile contenente la scheda aperta e quindi riempito l'URL dopo aver caricato i dati. Grazie. const tab = window.open(); observable.subscribe(dataUrl => tab.location.href = dataUrl);
jonas,

1
Se hai attivato il blocco popup, questo non risolverà il problema con il blocco popup ...
Alejandro Vales,

La soluzione jonas di @Alejandro Vales funzionerà solo se il codice verrà eseguito da un evento onClick o da qualsiasi interazione dell'utente. Quando provi ad aprire una nuova scheda tramite windows.open all'interno di una promessa, timeout, iscriviti ... il browser pensa che sia una manipolazione dell'utente, quindi la soluzione è creare un'istanza prima di inserire la promessa, dentro di te basta cambiare il brivido come faceva Jonas
David,

@ David Grazie mille !!! Non mi è capitato di vedere la .thenrisposta, quindi è per questo che mi sono così confuso: / SRY ...
Alejandro Vales,

@ David Questo è fantastico! Funziona come un fascino. Se potessi disturbarti con un'altra domanda, sai anche come farlo funzionare in Edge? Una spinta a una giusta risorsa sarebbe di grande aiuto ...
dzenesiz

21

Come buona pratica, penso che sia una buona idea verificare se un popup è stato bloccato e agire nel caso. Devi sapere che window.open ha un valore di ritorno e che il valore potrebbe essere nullo se l'azione non è riuscita. Ad esempio, nel seguente codice:

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

se il popup è bloccato, window.open restituirà null. Quindi la funzione restituirà false.

Ad esempio, immagina di chiamare questa funzione direttamente da qualsiasi collegamento con target="_blank": se il popup viene aperto correttamente, il ritorno falsebloccherà l'azione del collegamento, altrimenti se il popup è bloccato, il ritorno trueconsente il comportamento predefinito (apri la nuova finestra _blank) e continua .

<a href="http://whatever.com" target="_blank" onclick='return pop("http://whatever.com",300,200);' >

In questo modo avrai un popup se funziona e una finestra _blank in caso contrario.

Se il popup non si apre, è possibile:

  • apri una finestra vuota come nell'esempio e continua
  • apri un popup falso (un iframe all'interno della pagina)
  • informare l'utente ("si prega di consentire i popup per questo sito")
  • aprire una finestra vuota e quindi informare l'utente ecc.

Grazie. Lavorato!
Bcktr,

8

dall'API JavaScript oauth di Google:

http://code.google.com/p/google-api-javascript-client/wiki/Authentication

Vedi l'area dove si legge:

Impostazione dell'autenticazione

L'implementazione di OAuth 2.0 da parte del client utilizza una finestra popup per richiedere all'utente di accedere e approvare l'applicazione. La prima chiamata a gapi.auth.authorize può attivare i blocchi popup, in quanto apre indirettamente la finestra popup. Per impedire che il blocco popup si attivi nelle chiamate di autenticazione, chiamare gapi.auth.init (callback) quando viene caricato il client. Il callback fornito verrà eseguito quando la libreria è pronta per effettuare chiamate di autenticazione.

Immagino che sia relativo alla vera risposta sopra in come spiega se c'è una risposta immediata, non farà scattare l'allarme popup. Il "gapi.auth.init" lo sta facendo in modo che l'API avvenga immediatamente.

Applicazione pratica

Ho realizzato un microservizio di autenticazione open source utilizzando il passaporto del nodo su npm e i vari pacchetti di passaporto per ciascun provider. Ho usato un approccio di reindirizzamento standard alla terza parte assegnandogli un URL di reindirizzamento a cui tornare. Questo era programmatico, quindi potevo avere diversi posti in cui reindirizzare nuovamente in caso di accesso / iscrizione e su pagine particolari.

github.com/sebringj/athu

passportjs.org


3

Ho provato diverse soluzioni, ma la sua è l'unica che ha funzionato per me in tutti i browser

let newTab = window.open(); newTab.location.href = url;


2
Questo non funziona solo per le persone che hanno attivato il blocco dei popup
Alejandro Vales,

che cos'è url? non è assegnato.
Shinriyo,

@shinriyo url è il link a qualunque pagina tu voglia accedere, per esempiohttp://example.com
pomobc

@AlejandroVales ho il blocco popup abilitato e funziona. Il problema è che window.open()non è possibile aprire una nuova finestra a livello di codice e, se necessario, quella risposta è una delle opzioni. Con la newTabvariabile a cui facciamo riferimento window.open()e in seguito possiamo chiamarla, inserire il urlnecessario, nel mio caso l'URL di alcuni BLOB, e la nuova scheda verrà aperta con l'URL inserito.
stanimirsp,

0

Non volevo creare la nuova pagina a meno che il callback non fosse tornato correttamente, quindi l'ho fatto per simulare il clic dell'utente:

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

3
non funziona per me in Chrome 62. Popup (pagina) viene bloccato.
s.ermakovich,

1
Sì, hai ragione, ho anche scoperto che questo è incoerente. Ho finito per rendere la mia chiamata API sincrona
user3479425 il

-8

Il modo più semplice per sbarazzarsi di questo è:

  1. Non usare document.open ().
  2. Utilizzare invece this.document.location.href = location; dove location è l'URL da caricare

Es:

<script>
function loadUrl(location)
{
this.document.location.href = location;
}</script>

<div onclick="loadUrl('company_page.jsp')">Abc</div>

Questo ha funzionato molto bene per me. Saluti


2
Che ne dici di aprire l'URL in una nuova scheda?
3 regole
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.