Обхід блокуючого спливаючого вікна на window.open, коли встановлено JQuery event.preventDefault ()


98

Я хочу умовно показати діалог JQuery при події клацання гіперпосилання.

У мене є така вимога, як при умові1, відкрити діалог JQuery, і якщо умова1 не виконується, перейдіть на сторінку, на яку посилається тег 'href', про чию подію натискання йдеться.

Я можу викликати функцію на події клацання посилання. Ця функція тепер перевіряє вказану умову, виконавши іншу URL-адресу (яка виконує мій контролер Spring і повертає відповідь).

Все працює ідеально, лише блокуючи вікно блокування спливаючих вікон.

$('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);
        }
    });
});

Якщо я e.preventDefault();видаляю з коду, блокувальник спливаючих вікон не блокує сторінку, однак для умови1 він відкриває діалог, а також відкриває сторінку 'href'.

Якщо я вирішую одне, це створює питання для іншого. Я не в змозі одночасно поставити справедливість для обох умов.

Чи можете ви мені допомогти вирішити це питання?

Після того як це буде вирішено, у мене є ще одне питання, тобто навігація по порядку OK


1
намагайтеся не використовувати .live його застаріле і вказівник на .on ()!
мас-дизайни

@EvilP: Як інші говорили вам минулого разу, лише в 1.7 і вище. Дуже багато проектів все ще буде на 1,5 або 1,6.
TJ Crowder

10
Downvoter: Тільки тому, що вам не подобаються спливаючі вікна, це не означає, що це питання слід прихиляти. Питання повинно бути скасованим, якщо воно "... не показує жодних зусиль для дослідження; якщо воно є незрозумілим чи не корисним" . Питання зрозуміле, не здається ледачим, і випливає з нетривіального поєднання факторів.
TJ Crowder

@TJCrowder: Він не вказав, яку версію він використовує. Тому я повинен врахувати, що він використовує останню версію. Якщо він використовує іншу версію, я впевнений, що він зазначив би це тому, що ТОГО він би знав про те, що живий застарілий, і пояснив, ЧОМУ він використовує .live (). Ніхто ніколи не казав мені "останній" час, тому я думаю, ви повинні перепочити і заспокоїтися. Не потрібно бути таким суворим ...
mas-designs

Не отримали жодного повідомлення про це. Але чи не нормально вважати, що якщо хтось не вказав свою версію, то він вважає, що він використовує останню версію? Я маю на увазі, що я повинен використовувати 1.3 з причини, і я знаю про те, що є новіша і краща версія.
мас-дизайни

Відповіді:


144

Блокатори спливаючих вікон, як правило, дозволяються лише у window.openразі використання під час обробки події користувача (наприклад, клацання). У вашому випадку ви телефонуєте window.open пізніше , а не під час події, оскільки $.getJSONце асинхронно.

У вас є два варіанти:

  1. Робіть щось інше, а не window.open.

  2. Зробіть виклик Ajax синхронним, що зазвичай вам слід уникати, як чума, оскільки він блокує інтерфейс браузера. $.getJSONеквівалентно:

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

    ... і таким чином ви можете зробити ваш $.getJSONдзвінок синхронним, зіставивши парами до вищезазначеного та додавши 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);
            }
        }
    });

    Знову ж таки, я не виступаю за синхронні виклики ajax, якщо ви можете знайти інший спосіб досягти своєї мети. Але якщо ви не можете, ви йдете.

    Ось приклад коду, який не виконує тест через асинхронний виклик:

    Живий приклад | Пряме джерело (Живі посилання більше не працюють через зміни в 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");
        });
      });
    });

    Ось приклад, який працює, використовуючи синхронний дзвінок:

    Живий приклад | Пряме джерело (Живі посилання більше не працюють через зміни в 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");
          }
        });
      });
    });

3
Завдяки мільйонів. Ваша пропозиція зробити дзвінок синхронним спрацювала як принадність. Те ж саме допомогло мені в наступному моєму вірогідному наступному випуску по роботі з навігацією в рамках події OK.
mavaze

Оскільки TJ Crowder залишив відкритими 2 питання, [1. знайти альтернативу window.open] та [2. уникати синхронного дзвінка Ajax] пропозиції щодо цих пропозицій вітаються на користь громади. Інакше я знайшов його відповідь ідеальним рішенням на вказане запитання :)
марев

4
Для мене я додав посилання з target = "_ blank", щоб спонукати користувача натискати.
hiroshi

1
@Evan: Вам доведеться використовувати XHR безпосередньо. У квитку є приклад знецінення синхронних запитів .
TJ Crowder

2
@mavaze Я думаю, що ви можете уникнути обох проблем, якщо зможете змінити потік керування, щоб спершу відкрити вікно (синхронізувати), потім виконати запит AJax (async), а потім скористатися відповіддю або показати повідомлення про помилку, або зробити переадресацію.
Штійн де Вітт

61

Ви можете зателефонувати на window.open без блокування браузера, лише якщо користувач виконає якісь дії. Браузер надсилає якийсь прапор і визначає, що вікно відкрилося дією користувача.

Отже, ви можете спробувати цей сценарій:

  1. var myWindow = window.open ('')
  2. намалювати будь-яке повідомлення про завантаження у цьому вікні
  3. коли запит виконано, просто зателефонуйте myWindow.location = " http://google.com "

2
Це не працює на Safari Mobile (тестується на IPhone 4). Я спробував кілька інших ідей (наприклад myWindow.postMessage), але через обмеження Safaris не виконувати JavaScript у фоновому режимі, батьківське вікно ніколи не може надіслати цю зміну місцезнаходження.
круглий робін

@BausTheBig Я перевірив на iPhone 6, IOS8. Це спрацювало як шарм.
lvarayut

шукав спосіб відстежувати зовнішні зв’язки з Google Analytics, не блокуючи спливаюче вікно. Це саме те, що мені було потрібно. Здається, добре працює на iPhone 4s в iOS7 (власне телефон) та iOS 8 (iOS Simulator).
notacouch

37

У мене була ця проблема, і я не мав готового URL-адреси, поки зворотний виклик поверне деякі дані. Рішенням було відкрити порожнє вікно перед запуском зворотного дзвінка, а потім просто встановити місце, коли зворотний виклик повернеться.

$scope.testCode = function () {
    var newWin = $window.open('', '_blank');
    service.testCode().then(function (data) {
        $scope.testing = true;
        newWin.location = '/Tests/' + data.url.replace(/["]/g, "");
    });
};

1
Я використовував це рішення, щоб відкрити нове вікно та обійти popupblocker
VeldMuijz

Що робити, якщо я не знаю заздалегідь, чи потрібно мені відкрити спливаюче вікно? Як у: action().then(doWindowOpenThing).catch(doSomethingElseThatDoesntOpenAPopup) Отже, я не можу відкрити вікно перед рукою (щоб зберегти його посилання тощо), якщо згодом я не буду його використовувати, правда?
Луїз

Ні, це відкриватиме нову вкладку кожного разу, і, мабуть, ви цього не хотіли б у випадку, коли ви не використовуєте її. Річ у тім, що браузер дозволить вам відкрити нову вкладку у функції клацання (ініційована користувачем дія), інакше блокувальник спливаючих вікон побачить це як сценарій відкриття нової вкладки без дозволу користувача та заблокує її.
KnuturO

Будь ласка, зробіть тест, якщо newWin недійсний!
FrancescoMM

Чому? Я не бачу причин для цього.
KnuturO

18

спробуйте це, це працює для мене,

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

Є загадкою для цього http://jsfiddle.net/safeeronline/70kdacL4/1/


1
Дякую, працювали і для мене - якби не ця загадка, я, мабуть, не повірив би, лол!
rmcsharry

3
Це має бути прийнята відповідь! Ви також можете використовувати redirectWindow.location.assign ('new_url'), якщо вам потрібні дані про асинхронізацію для створення URL-адреси.
matheusr

Приємне рішення.
Підтримай

Будь ласка, зробіть тест, якщо redirectWindow недійсний! За різними параметрами браузера ви можете заблокувати чи ні.
FrancescoMM

8

Windows має бути створено на тому ж стеку (він же мікрозадача ), що ініційований користувачем подією, наприклад, зворотній виклик клацання, тому вони не можуть бути створені пізніше, асинхронно.

Однак ви можете створити вікно без URL-адреси, а потім зможете змінити URL-адресу цього вікна, як тільки це знаєте , навіть асинхронно!

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

Сучасні браузери відкриють вікно з порожньою сторінкою (часто її називають about:blank), і якщо припустити, що ваше завдання асинхронізації отримати URL-адресу є досить швидким, результат UX здебільшого добре. Якщо натомість ви хочете вивести повідомлення про завантаження (або що-небудь) у вікно, поки користувач чекає, ви можете використовувати URI даних .

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

3

Цей код допоможе мені. Сподіваюся, це допоможе деяким людям

$('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';

    });
});

3

Спробуйте скористатись елементом посилання та натисніть на нього за допомогою javascriipt

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

і сценарій

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

Використовуйте його так

//do stuff
var id = 123123141;
openURL("/api/user/" + id + "/print") //this open webpage bypassing pop-up blocker
openURL("https://www.google.com") //Another link

Це уникало стикатися з порожнім вікном для мене.
ponder275

Виявилося, це не вирішило мою проблему, коли iPhone блокував моє вікно як спливаюче вікно.
ponder275

2

Спостереження, що користувач повинен був ініціювати подію, допомогло мені з’ясувати першу частину цього, але навіть після цього Chrome і Firefox все-таки заблокували нове вікно. Друга частина додала target = "_ blank" до посилання, про яке згадувалося в одному коментарі.

Підсумовуючи: вам потрібно зателефонувати window.open з події, ініційованої користувачем, в цьому випадку натиснути на посилання, і це посилання має мати target = "_ blank".

У наведеному нижче прикладі посилання використовує class = "кнопка-щебетання".

$('.button-twitter').click(function(e) {
  e.preventDefault();
  var href = $(this).attr('href');
  var tweet_popup = window.open(href, 'tweet_popup', 'width=500,height=300');
});


1

Я використовую цей метод, щоб уникнути блокуючого спливаючого вікна в моєму коді React. він також буде працювати у всіх інших кодах javascript.

Коли ви здійснюєте виклик асинхронізації під час події клацання, просто відкрийте спочатку порожнє вікно, а потім напишіть URL-адресу пізніше, коли завершиться виклик асинхронізації.

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

про успіх асинхронного дзвінка напишіть наступне

popupWindow.document.write(resonse.url)
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.