Hindari pemblokir popup browser

172

Saya sedang mengembangkan alur otentikasi OAuth murni dalam JavaScript dan saya ingin menunjukkan kepada pengguna jendela "beri akses" dalam sembulan, tetapi diblokir.

Bagaimana saya bisa mencegah jendela sembulan yang dibuat oleh window.openatau window.showModalDialogdiblokir oleh pemblokir pop-up browser yang berbeda?

Pablo Fernandez
sumber
11
Bahkan jika itu mungkin (saya tidak tahu), jika orang menggunakan pemblokir popup Anda harus menghormatinya. Sebagian besar browser menampilkan pesan ketika sebuah situs mencoba membuka sembulan sehingga mereka masih dapat melihatnya jika mereka mau. Anda dapat memberi komentar di situs Anda bahwa beberapa konten terbuka di sembulan dan pengguna harus mengizinkannya untuk melanjutkan.
Felix Kling
5
Praktik terbaik akan terlihat seperti: 1) Lakukan ini dengan sukses 2) Bidik jendela Anda dan batasi pintu Anda dan gemetar ketakutan dari kerumunan pengunjung web-pelanggan yang marah 3) Bertobat, singkirkan pop-up-busta-busta, dan hormati audiens Anda.
Alex Mcp
Alex dan Felix, saya sudah memperbarui pertanyaannya. Saya tidak akan menggunakan pengetahuan untuk kejahatan :). Terima kasih!
Pablo Fernandez
9
Saya ingin menambahkan bahwa melewati pemblokir popup mungkin sebenarnya mencoba membuat pengalaman pengguna lebih baik. Dalam contoh yang saya kerjakan sekarang, kami menggunakan aplikasi Javascript (berdasarkan ExtJS) dan kami mencoba untuk membiarkan pengguna membayar menggunakan paypal. Kami memberi mereka tombol yang dapat mereka klik untuk meluncurkan paypal di jendela baru, tetapi versi IE tertentu memblokirnya sebagai sembulan (meskipun itu adalah klik tombol). Jika sekarang mereka mengaktifkan popup, layar memuat ulang dan sebagai aplikasi JavaScript, kita kehilangan status jendela dan mereka harus memulai dari awal. Jadi sungguh: masalahnya adalah IE bodoh.
NateDSaint
1
@ Feliksling Ya itu mungkin. Pembuat browser sudah memikirkan hal ini. Membuka popup adalah OK sejauh ada niat pengguna (ditandai oleh pengguna mengklik tautan atau tombol). Pemblokir popup harus menghormati maksud pengguna. Jika pemblokir popup IE tidak, itu pemblokir popup yang salah. Pengguna menggunakan pemblokir popup untuk mencegah skrip membuka popup sesuka hati, bukan untuk memblokir popup yang mereka coba buka sendiri (dengan mengklik tombol atau tautan).
Stijn de Witt

Jawaban:

286

Aturan umum adalah bahwa pemblokir popup akan terlibat jika window.openatau serupa dipanggil dari javascript yang tidak dipanggil oleh tindakan pengguna langsung . Artinya, Anda dapat menelepon window.opensebagai respons terhadap klik tombol tanpa terkena popup blocker, tetapi jika Anda memasukkan kode yang sama dalam acara penghitung waktu, itu akan diblokir. Kedalaman rantai panggilan juga merupakan faktor - beberapa browser lama hanya melihat penelepon langsung, browser yang lebih baru dapat mundur sedikit untuk melihat apakah penelepon penelepon adalah klik mouse, dll. Simpan semurah mungkin untuk menghindari pemblokir popup.

dthorpe
sumber
2
Menariknya, munculan yang dimulai melalui acara perubahan yang terikat ke elemen tertentu akan diblokir (di Chrome, bukan FF), meskipun acara tersebut diawali oleh tindakan pengguna langsung, seperti klik. Meskipun jika terikat pada input, mereka diizinkan. Aneh.
ccnokes
6
Tidak ada yang mengatakan browser konsisten. : P
dthorpe
8
Melalui percobaan saya harus memahami bahwa kedalaman tumpukan tidak ada hubungannya dengan pemblokir popup. Ini benar-benar memeriksa apakah window.open dipanggil dalam 1 detik setelah aksi pengguna atau tidak. Diuji di Chrome 46 dan Firefox 42.
Mesqalito
Timeout 1 detik dapat dielakkan di kedua browser yang memungkinkan untuk waktu yang tidak terbatas menggunakan jawaban oleh @ tj-crowder di halaman ini .. punya URL yang Anda panggil melalui ajax menjadi beberapa php (atau apa pun) yang menggunakan sleep ( ) untuk sejumlah waktu sebelum mengembalikan respons. Peramban akan hang ketika 'memuat' halaman .. kemudian memicu sembulan ketika menerima respons. Di Chrome, Anda harus menambahkan lansiran () tepat sebelum ajax () agar trik ini berfungsi.
keriuhan
184

Berdasarkan Jason Sebring Ini tip yang sangat berguna , dan pada hal-hal yang dibahas di sini dan di sana , saya menemukan solusi sempurna untuk kasus saya:

Kode semu dengan cuplikan Javascript:

  1. segera buat popup kosong pada aksi pengguna

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

    Opsional: tambahkan beberapa pesan info "menunggu". Contoh:

    a) Halaman HTML eksternal: ganti baris di atas dengan

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

    b) Teks: tambahkan baris berikut di bawah yang di atas:

    importantStuff.document.write('Loading preview...');
  2. isi dengan konten saat siap (ketika panggilan AJAX dikembalikan, misalnya)

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

Perkaya panggilan untuk window.open dengan opsi tambahan apa pun yang Anda butuhkan.

Saya sebenarnya menggunakan solusi ini untuk pengalihan mailto, dan itu berfungsi pada semua browser saya (windows 7, Android). Itu_blank bit membantu untuk mailto redirection untuk bekerja pada ponsel, btw.

Pengalamanmu? Adakah cara untuk meningkatkan ini?

Tuan Swiss
sumber
1
? jadi apa yang Anda lakukan jika itu bukan dari tindakan pengguna di browser? Sebagai contoh saya, setelah pengguna mengautentikasi terhadap server, itu harus membuka tab baru
Don Cheadle
@mmcrae jangan lakukan itu. Apa pun yang ingin Anda lakukan, ada cara yang lebih baik daripada jendela sembulan. Kalau tidak, kemungkinan saya tidak akan pernah ingin melihat situs Anda. Peramban hari ini memastikan Anda tidak akan bisa melakukan itu - lihat jawaban @dthorpe .
Swiss Mister
5
Whatever it is you intend to do, there is a better way than a popup windowlol? Generalisasi ganjil. Klien ingin halaman yang diautentikasi agar tetap terbuka, dan halaman situs / pendaratan baru setelah otentikasi dibuka di tab baru. Ya, bukan ide saya tentang pengalaman pengguna yang sangat baik ... tetapi tampaknya masuk akal
Don Cheadle
@mmcrae Duduk dan pikirkan, serius. Saya berjanji kepada Anda bahwa Anda akan menemukan "aksi pengguna" dalam skenario yang Anda jelaskan. Inti dari jawaban saya adalah Anda membuat jendela sembulan saat Anda memiliki tindakan pengguna - dan kemudian mengisinya dengan konten. Petunjuk untuk kasus Anda: pengguna mengklik "otentikasi" -> buat munculan (kosong); timer habis atau respons server kembali atau apa pun -> isi konten ke dalam sembulan.
Swiss Mister
3
Kiat bermanfaat, jika permintaan ajax gagal, panggil importantStuff.closeuntuk menutup tab baru dan berikan dan beri tahu di halaman asli.
Angsa
24

Selain posting Swiss Mister, dalam kasus saya window.open diluncurkan di dalam janji, yang mengaktifkan pemblokir popup, solusi saya adalah: dalam sudut:

$scope.gotClick = function(){

  var myNewTab = browserService.openNewTab();
  someService.getUrl().then(
    function(res){
        browserService.updateTabLocation(res.url, myNewTab);

    }
  );
};

layanan browser:

this.openNewTab = function(){
     var newTabWindow = $window.open();
     return newTabWindow;
}

this.updateTabLocation = function(tabLocation, tab) {
     if(!tabLocation){
       tab.close();
     }
     tab.location.href = tabLocation;
}

ini adalah bagaimana Anda dapat membuka tab baru menggunakan respons janji dan tidak memanggil pemblokir popup.

David
sumber
1
Ini menyebabkan solusi saya! Di mana saya membuat variabel yang berisi tab yang dibuka, dan kemudian mengisi url setelah data dimuat. Terima kasih. const tab = window.open(); observable.subscribe(dataUrl => tab.location.href = dataUrl);
Jonas
1
Jika Anda mengaktifkan pemblokir popup ini tidak akan memperbaiki masalah dengan pemblokir popup ...
Alejandro Vales
Solusi @Alejandro Vales jonas hanya akan berfungsi jika kode akan berjalan dari peristiwa onClick, atau interaksi pengguna apa pun. Ketika Anda mencoba untuk membuka tab baru melalui windows.buka di dalam janji, batas waktu, berlangganan ... browser berpikir itu adalah manipulasi pada pengguna, jadi solusinya adalah membuat contoh sebelum memasukkan janji, di dalam Anda hanya mengubah href seperti yang dilakukan jonas
David
@ David Terima kasih banyak !!! Saya tidak kebetulan melihat .thenjawaban saat itu dan itulah sebabnya saya jadi bingung: / SRY ...
Alejandro Vales
@ David Ini luar biasa! Bekerja seperti pesona. Jika saya dapat mengganggu Anda dengan satu pertanyaan lagi - apakah Anda tahu cara membuat ini bekerja di Edge, juga? Dorongan ke sumber daya yang tepat akan sangat membantu ...
dzenesiz
21

Sebagai praktik yang baik, saya pikir itu ide yang baik untuk menguji apakah popup diblokir dan mengambil tindakan untuk berjaga-jaga. Anda perlu tahu bahwa window.open memiliki nilai kembali, dan nilai itu mungkin nol jika tindakan gagal. Misalnya, dalam kode berikut:

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

jika popup diblokir, window.open akan mengembalikan nol. Jadi fungsinya akan mengembalikan false.

Sebagai contoh, bayangkan memanggil fungsi ini langsung dari tautan apa pun dengan target="_blank": jika popup berhasil dibuka, kembali falseakan memblokir tindakan tautan, jika tidak, popup diblokir, kembali trueakan membiarkan perilaku default (buka jendela _blank baru) dan lanjutkan .

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

Dengan cara ini Anda akan memiliki popup jika berfungsi, dan jendela _blank jika tidak.

Jika popup tidak terbuka, Anda dapat:

  • buka jendela kosong seperti pada contoh dan lanjutkan
  • buka sembulan palsu (iframe di dalam laman)
  • informasikan kepada pengguna ("perkenankan popup untuk situs ini")
  • buka jendela kosong lalu beri tahu pengguna dll.
FrancescoMM
sumber
Terima kasih. Bekerja!
Bcktr
8

dari API JavaScript Google oauth:

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

Lihat area di mana tertulis:

Menyiapkan Otentikasi

Implementasi klien dari OAuth 2.0 menggunakan jendela sembulan untuk meminta pengguna untuk masuk dan menyetujui aplikasi. Panggilan pertama ke gapi.auth.authorize dapat memicu pemblokir popup, karena membuka jendela popup secara tidak langsung. Untuk mencegah pemblokir popup memicu panggilan auth, panggil gapi.auth.init (panggilan balik) saat klien memuat. Callback yang disediakan akan dieksekusi ketika perpustakaan siap untuk melakukan panggilan auth.

Saya kira itu berkaitan dengan jawaban nyata di atas dalam cara menjelaskan jika ada tanggapan langsung, itu tidak akan trip alarm popup. "Gapi.auth.init" membuatnya sehingga api segera terjadi.

Aplikasi praktis

Saya membuat microservice otentikasi open source menggunakan paspor simpul pada npm dan berbagai paket paspor untuk setiap penyedia. Saya menggunakan pendekatan pengalihan standar ke pihak ke-3 yang memberikan URL pengalihan untuk kembali ke. Ini terprogram sehingga saya dapat memiliki tempat yang berbeda untuk mengarahkan kembali ke jika login / mendaftar dan pada halaman tertentu.

github.com/sebringj/athu

passportjs.org

Jason Sebring
sumber
3

Saya mencoba beberapa solusi, tetapi hanya dia yang benar-benar bekerja untuk saya di semua browser

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

pomobc
sumber
2
Ini tidak berfungsi untuk orang yang mengaktifkan pemblokir popup
Alejandro Vales
apa url? itu tidak ditugaskan.
shinriyo
@shinriyo url adalah tautan ke halaman apa pun yang ingin Anda akses, misalnyahttp://example.com
pomobc
@AlejandroVales saya mengaktifkan pemblokir popup dan berfungsi. Masalahnya adalah bahwa window.open()tidak dapat membuka jendela baru secara terprogram dan jika perlu, jawaban itu adalah salah satu opsi. Dengan newTabvariabel kita membuat referensi window.open()dan kemudian kita dapat memanggilnya, masukkan yang urlkita butuhkan, dalam url kasus saya dari beberapa gumpalan, dan tab baru akan dibuka dengan pada url yang dimasukkan.
stanimirsp
0

Saya tidak ingin membuat halaman baru kecuali panggilan balik berhasil kembali, jadi saya melakukan ini untuk mensimulasikan klik pengguna:

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);
  });
}
pengguna3479425
sumber
3
tidak berfungsi untuk saya di Chrome 62. Popup (halaman) diblokir.
s.ermakovich
1
Ya Anda benar - saya juga menemukan ini tidak konsisten. Saya akhirnya membuat panggilan api saya sinkron
user3479425
-8

Cara termudah untuk menghilangkan ini adalah dengan:

  1. Jangan gunakan document.open ().
  2. Alih-alih gunakan this.document.location.href = lokasi; di mana lokasi adalah url yang akan dimuat

Mis:

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

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

Ini bekerja sangat baik untuk saya. Bersulang

Pramod Shetty
sumber
2
Bagaimana dengan membuka url di tab baru?
3 aturan