Bypass popup blocker di window.open saat JQuery event.preventDefault () disetel

98

Saya ingin menampilkan dialog JQuery secara kondisional pada acara klik hyperlink.

Saya memiliki persyaratan seperti pada condition1 buka dialog JQuery dan jika condition1 tidak terpenuhi, navigasikan ke halaman seperti yang direferensikan oleh tag 'href' yang peristiwa kliknya dipertanyakan.

Saya dapat memanggil fungsi pada acara klik tautan. Fungsi ini sekarang memeriksa kondisi tersebut dengan menjalankan URL lain (yang mengeksekusi pengontrol Spring saya dan mengembalikan respons).

Semua bekerja sempurna hanya dengan window.open diblokir oleh pemblokir popup.

$('a[href*=/viewpage?number]').live('click', function(e) {
    e.preventDefault();
    redirectionURL = this.href;
    pageId= getUrlVars(redirectionURL)["number"];
    $.getJSON("redirect/" + pageId, {}, function(status) {
        if (status == null) {
            alert("Error in verifying the status.");
        } else if(!status) {
            $("#agreement").dialog("open");
        } else {
            window.open(redirectionURL);
        }
    });
});

Jika saya menghapus e.preventDefault();dari kode, popoup blocker tidak memblokir halaman, namun untuk condition1 maka akan membuka dialog sekaligus membuka halaman 'href'.

Jika saya menyelesaikan satu masalah, itu menimbulkan masalah bagi orang lain. Saya tidak bisa memberikan keadilan pada kedua kondisi secara bersamaan.

Bisakah Anda membantu saya mengatasi masalah ini?

Setelah ini diselesaikan, saya memiliki masalah lain untuk dipecahkan yaitu navigasi pada acara OK dialog :)

labirin
sumber
1
cobalah untuk tidak menggunakan .live yang sudah usang dan penunjuk ke .on ()!
desain-mas
@EvilP: Seperti yang dikatakan orang lain kepada Anda terakhir kali, hanya di 1.7 dan lebih tinggi. Sebuah banyak proyek masih akan berada di 1,5 atau 1,6.
TJ Crowder
10
Downvoter: Hanya karena Anda tidak menyukai pop-up, bukan berarti pertanyaan ini harus diremehkan. Sebuah pertanyaan harus diturunkan suara jika "... tidak menunjukkan upaya penelitian apa pun; jika tidak jelas atau tidak berguna" . Pertanyaannya jelas, tidak tampak malas, dan berasal dari kombinasi faktor-faktor yang tidak sepele.
TJ Crowder
@TJCrowder: Dia tidak menentukan versi mana yang dia gunakan. Jadi saya harus mempertimbangkan bahwa dia menggunakan versi terbaru. Jika dia menggunakan versi yang berbeda, saya yakin dia akan menyebutkannya karena KEMUDIAN dia AKAN menyadari fakta bahwa live sudah usang dan akan menjelaskan MENGAPA dia menggunakan .live (). Tidak ada yang pernah memberi tahu saya waktu "terakhir" jadi saya rasa Anda harus istirahat dan tenang. Tidak perlu terlalu kasar ...
desain-mas
Tidak mendapat pemberitahuan apapun tentang itu. Tetapi bukankah normal untuk mempertimbangkan bahwa jika seseorang tidak menentukan versinya untuk mempertimbangkan bahwa mereka menggunakan yang terbaru? Maksud saya, saya harus menggunakan 1.3 karena suatu alasan dan saya menyadari fakta bahwa ada versi yang lebih baru dan lebih baik.
desain-mas

Jawaban:

144

Pemblokir popup biasanya hanya akan mengizinkan window.openjika digunakan selama pemrosesan acara pengguna (seperti klik). Dalam kasus Anda, Anda menelepon window.open nanti , bukan selama acara, karena $.getJSONasinkron.

Anda memiliki dua pilihan:

  1. Lakukan sesuatu yang lain, daripada window.open.

  2. Buat panggilan ajax sinkron, yang biasanya Anda hindari seperti wabah karena mengunci UI browser. $.getJSONsetara dengan:

    $.ajax({
      url: url,
      dataType: 'json',
      data: data,
      success: callback
    });
    

    ... dan agar Anda dapat membuat $.getJSONpanggilan Anda sinkron dengan memetakan parameter Anda di atas dan menambahkan async: false:

    $.ajax({
        url:      "redirect/" + pageId,
        async:    false,
        dataType: "json",
        data:     {},
        success:  function(status) {
            if (status == null) {
                alert("Error in verifying the status.");
            } else if(!status) {
                $("#agreement").dialog("open");
            } else {
                window.open(redirectionURL);
            }
        }
    });
    

    Sekali lagi, saya tidak menganjurkan panggilan ajax sinkron jika Anda dapat menemukan cara lain untuk mencapai tujuan Anda. Tetapi jika Anda tidak bisa, ini dia.

    Berikut adalah contoh kode yang gagal dalam pengujian karena panggilan asinkron:

    Contoh langsung | Sumber langsung (Tautan langsung tidak lagi berfungsi karena perubahan pada JSBin)

    jQuery(function($) {
      // This version doesn't work, because the window.open is
      // not during the event processing
      $("#theButton").click(function(e) {
        e.preventDefault();
        $.getJSON("http://jsbin.com/uriyip", function() {
          window.open("http://jsbin.com/ubiqev");
        });
      });
    });
    

    Dan inilah contoh yang berhasil, menggunakan panggilan sinkron:

    Contoh langsung | Sumber langsung (Tautan langsung tidak lagi berfungsi karena perubahan pada JSBin)

    jQuery(function($) {
      // This version does work, because the window.open is
      // during the event processing. But it uses a synchronous
      // ajax call, locking up the browser UI while the call is
      // in progress.
      $("#theButton").click(function(e) {
        e.preventDefault();
        $.ajax({
          url:      "http://jsbin.com/uriyip",
          async:    false,
          dataType: "json",
          success:  function() {
            window.open("http://jsbin.com/ubiqev");
          }
        });
      });
    });
    
TJ Crowder
sumber
3
Terima kasih banyak. Saran Anda untuk membuat panggilan sinkron bekerja seperti pesona. Hal yang sama membantu saya dalam kemungkinan edisi berikutnya dalam menangani navigasi pada acara dialog OK.
mavaze
Karena TJ Crowder telah meninggalkan 2 pertanyaan terbuka, [1. mencari alternatif untuk window.open] dan [2. menghindari panggilan sinkron ajax] saran tersebut diterima untuk kepentingan komunitas. Lain saya menemukan jawabannya solusi sempurna untuk pertanyaan tersebut :)
mavaze
4
Bagi saya, saya menambahkan link dengan target = "_ blank" untuk meminta pengguna mengklik.
hiroshi
1
@ Evan: Anda harus menggunakan XHR secara langsung. Ada contoh di tiket untuk menghentikan permintaan sinkron .
TJ Crowder
2
@mavaze Saya rasa Anda dapat menghindari kedua masalah tersebut jika Anda dapat mengubah aliran kontrol untuk membuka jendela terlebih dahulu, (sinkronkan), kemudian lakukan permintaan AJax (asinkron) dan kemudian gunakan respons untuk menampilkan pesan kesalahan atau melakukan pengalihan.
Stijn de Witt
61

Anda dapat memanggil window.open tanpa pemblokiran browser hanya jika pengguna melakukan beberapa tindakan secara langsung. Browser mengirimkan beberapa tanda dan menentukan bahwa jendela dibuka oleh tindakan pengguna.

Jadi, Anda bisa mencoba skenario ini:

  1. var myWindow = window.open ('')
  2. gambar pesan pemuatan apa pun di jendela ini
  3. ketika permintaan selesai, cukup hubungi myWindow.location = ' http://google.com '
Evgeniy Kubyshin
sumber
2
Ini tidak berfungsi di Safari Mobile (diuji di IPhone 4). Saya mencoba beberapa ide lain (misalnya myWindow.postMessage) tetapi karena batasan Safaris untuk tidak menjalankan JavaScript di latar belakang, jendela induk tidak pernah dapat mengirim perubahan lokasi tersebut.
roundrobin
@BausTheBig Saya uji pada iPhone 6, IOS8. Ini bekerja seperti pesona.
lvarayut
sedang mencari cara untuk melacak tautan eksternal dengan Google Analytics tanpa memblokir munculan. Inilah yang saya butuhkan. Tampaknya berfungsi dengan baik di iPhone 4s di iOS7 (ponsel sebenarnya) dan iOS 8 (iOS Simulator).
notacouch
37

Saya mengalami masalah ini dan saya tidak memiliki url saya sampai callback akan mengembalikan beberapa data. Solusinya adalah membuka jendela kosong sebelum memulai panggilan balik dan kemudian hanya mengatur lokasi saat panggilan balik kembali.

$scope.testCode = function () {
    var newWin = $window.open('', '_blank');
    service.testCode().then(function (data) {
        $scope.testing = true;
        newWin.location = '/Tests/' + data.url.replace(/["]/g, "");
    });
};
KnuturO
sumber
1
Saya menggunakan solusi ini untuk membuka jendela baru dan melewati popupblocker
VeldMuijz
Bagaimana jika saya tidak tahu sebelumnya apakah saya perlu membuka munculan? Seperti dalam: action().then(doWindowOpenThing).catch(doSomethingElseThatDoesntOpenAPopup) Jadi saya tidak bisa membuka jendela sebelumnya (untuk menyimpan referensi, dll) jika nanti saya tidak akan menggunakannya, bukan?
Luiz
Tidak, itu akan membuka tab baru setiap saat dan saya rasa Anda tidak akan menginginkannya jika Anda tidak menggunakannya. Masalahnya adalah browser hanya akan memungkinkan Anda untuk membuka tab baru dalam fungsi klik (tindakan yang dimulai oleh pengguna) jika tidak, pemblokir popup akan melihat ini sebagai skrip yang membuka tab baru tanpa izin pengguna dan memblokirnya.
KnuturO
Tolong, lakukan tes jika newWin nol!
FrancescoMM
Kenapa? Saya tidak melihat alasan untuk ini.
KnuturO
18

coba ini, ini berhasil untuk saya,

$('#myButton').click(function () {
    var redirectWindow = window.open('http://google.com', '_blank');
    $.ajax({
        type: 'POST',
        url: '/echo/json/',
        success: function (data) {
            redirectWindow.location;
        }
    });
});

Apakah biola untuk http://jsfiddle.net/safeeronline/70kdacL4/1/ ini

Mohammed Safeer
sumber
1
Terima kasih, bekerja untuk saya juga - jika bukan karena biola itu, saya mungkin tidak akan percaya, lol!
rmcsharry
3
Ini harus menjadi jawaban yang diterima! Anda juga dapat menggunakan redirectWindow.location.assign ('new_url') jika Anda memerlukan data asinkron untuk membuat url.
matheusr
Solusi bagus.
Pertahankan
Silakan, lakukan pengujian jika redirectWindow null! Menurut opsi browser yang berbeda Anda bisa diblokir atau tidak.
FrancescoMM
8

Windows harus dibuat pada tumpukan yang sama (alias microtask ) dengan kejadian yang dimulai oleh pengguna, misalnya panggilan balik klik - sehingga tidak dapat dibuat nanti, secara asinkron.

Namun, Anda dapat membuat jendela tanpa URL dan kemudian Anda dapat mengubah URL jendela itu setelah Anda mengetahuinya , bahkan secara asinkron!

window.onclick = () => {
  // You MUST create the window on the same event
  // tick/stack as the user-initiated event (e.g. click callback)
  const googleWindow = window.open();

  // Do your async work
  fakeAjax(response => {
    // Change the URL of the window you created once you
    // know what the full URL is!
    googleWindow.location.replace(`https://google.com?q=${response}`);
  });
};

function fakeAjax(callback) {
  setTimeout(() => {
    callback('example');
  }, 1000);
}

Browser modern akan membuka jendela dengan halaman kosong (sering disebut about:blank), dan dengan asumsi tugas asinkron Anda untuk mendapatkan URL cukup cepat, UX yang dihasilkan baik-baik saja. Jika Anda malah ingin merender pesan pemuatan (atau apa pun) ke jendela saat pengguna menunggu, Anda bisa menggunakan URI Data .

window.open('data:text/html,<h1>Loading...<%2Fh1>');
jayphelps
sumber
3

Kode ini membantu saya. Semoga ini membantu beberapa orang

$('formSelector').submit( function( event ) {

    event.preventDefault();

    var newWindow = window.open('', '_blank', 'width=750,height=500');

    $.ajax({

        url: ajaxurl,
        type: "POST",
        data: { data },

    }).done( function( response ) {

        if ( ! response ) newWindow.close();
        else newWindow.location = '/url';

    });
});
Richard
sumber
3

Coba gunakan elemen tautan dan klik dengan javascriipt

<a id="SimulateOpenLink" href="#" target="_blank" rel="noopener noreferrer"></a>

dan naskahnya

function openURL(url) {
    document.getElementById("SimulateOpenLink").href = url
    document.getElementById("SimulateOpenLink").click()
}

Gunakan seperti ini

//do stuff
var id = 123123141;
openURL("/api/user/" + id + "/print") //this open webpage bypassing pop-up blocker
openURL("https://www.google.com") //Another link
Fernando Carvajal
sumber
Ini menghindari berurusan dengan jendela kosong untuk saya.
ponder275
Ternyata ini tidak menyelesaikan masalah saya dengan iPhone yang memblokir jendela saya sebagai pop-up.
ponder275
2

Pengamatan bahwa acara harus dimulai oleh pengguna membantu saya untuk mengetahui bagian pertama dari ini, tetapi bahkan setelah itu Chrome dan Firefox masih memblokir jendela baru. Bagian kedua menambahkan target = "_ blank" ke tautan, yang disebutkan dalam satu komentar.

Singkatnya: Anda perlu memanggil window.open dari peristiwa yang dimulai oleh pengguna, dalam hal ini mengklik link, dan link tersebut harus memiliki target = "_ blank".

Pada contoh di bawah, tautannya menggunakan class = "button-twitter".

$('.button-twitter').click(function(e) {
  e.preventDefault();
  var href = $(this).attr('href');
  var tweet_popup = window.open(href, 'tweet_popup', 'width=500,height=300');
});
Alexis Bellido
sumber
2
var url = window.open("", "_blank");
url.location = "url";

ini berhasil untuk saya.

Diego Santa Cruz MendezĂș
sumber
1

Saya menggunakan metode ini untuk menghindari pemblokir popup di kode React saya. itu akan bekerja di semua kode javascript lainnya juga.

Saat Anda membuat panggilan asinkron pada peristiwa klik, cukup buka jendela kosong terlebih dahulu dan kemudian tulis URL di dalamnya nanti saat panggilan asinkron akan selesai.

const popupWindow = window.open("", "_blank");
popupWindow.document.write("<div>Loading, Plesae wait...</div>")

jika panggilan async berhasil, tulis kalimat berikut

popupWindow.document.write(resonse.url)
Tabish
sumber