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

98

Я хочу отображать диалоговое окно JQuery условно при щелчке гиперссылки.

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

Я могу вызвать функцию при нажатии на ссылку. Эта функция теперь проверяет указанное условие, выполняя другой URL-адрес (который выполняет мой контроллер Spring и возвращает ответ).

Все работает отлично, только window.open блокируется блокировщиком всплывающих окон.

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

Если я решу одно, это создаст проблемы для другого. Я не могу одновременно оценить оба условия.

Не могли бы вы помочь мне решить эту проблему?

Как только это будет решено, мне нужно будет решить еще одну проблему, например, навигацию по событию ОК в диалоге :)

мавазе
источник
1
старайтесь не использовать .live его устаревший и указатель на .on ()!
mas-designs
@EvilP: Как вам говорили в прошлый раз, только в версии 1.7 и выше. Еще много проектов будет на 1.5 или 1.6.
TJ Crowder
10
Голосующий против: То, что вам не нравятся всплывающие окна, не означает, что этот вопрос должен быть отклонен. За вопрос следует проголосовать против, если он «... не показывает никаких исследовательских усилий; если он неясен или бесполезен» . Вопрос ясен, не кажется ленивым и возникает из нетривиального сочетания факторов.
TJ Crowder
@TJCrowder: Он не уточнил, какую версию использует. Поэтому я должен учитывать, что он использует последнюю версию. Если он использует другую версию, я уверен, что он упомянул бы об этом, потому что ТОГДА он БУДАЛ бы знать о том, что live устарел, и объяснил бы, ПОЧЕМУ он использует .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");
          }
        });
      });
    });
TJ Crowder
источник
3
Бесконечно благодарен. Ваше предложение сделать вызов синхронным сработало как шарм. То же самое помогло мне в моей возможной следующей проблеме обработки навигации по событию OK диалога.
mavaze
Поскольку TJ Crowder оставил открытыми 2 вопроса, [1. найдите альтернативу window.open] и [2. избегайте синхронного вызова ajax] предложения по ним приветствуются на благо сообщества. Иначе я нашел его ответ идеальным решением для указанного вопроса :)
mavaze 02
4
Для меня я добавил ссылку с target = "_ blank", чтобы пользователь мог щелкнуть.
hiroshi
1
@Evan: Вам придется использовать XHR напрямую. В билете есть пример отказа от синхронных запросов .
TJ Crowder
2
@mavaze Я думаю, что вы можете избежать обеих проблем, если вы можете изменить поток управления, чтобы сначала открыть окно (синхронизация), затем выполнить запрос AJax (асинхронный), а затем использовать ответ, чтобы либо показать сообщение об ошибке, либо выполнить перенаправление.
Stijn de Witt
61

вы можете вызвать window.open без блокировки браузера, только если пользователь выполняет какое-либо действие напрямую. Браузер отправляет какой-то флаг и определяет, что окно открывается действием пользователя.

Итак, вы можете попробовать такой сценарий:

  1. var myWindow = window.open ('')
  2. нарисуйте любое сообщение о загрузке в этом окне
  3. когда запрос выполнен, просто вызовите myWindow.location = ' http://google.com '
Евгений Кубышин
источник
2
Это не работает в Safari Mobile (проверено на IPhone 4). Я пробовал несколько других идей (например myWindow.postMessage), но из-за ограничения Safaris на выполнение JavaScript в фоновом режиме, родительское окно никогда не может отправить это изменение местоположения.
roundrobin
@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, "");
    });
};
KnuturO
источник
1
Я использовал это решение, чтобы открыть новое окно и обойти блокировщик
всплывающих
Что делать, если я не знаю заранее, нужно ли мне открывать всплывающее окно? Как и в: 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-адреса выполняется довольно быстро, то в результате пользовательский интерфейс в целом удовлетворителен. Если вместо этого вы хотите отобразить сообщение о загрузке (или что-то еще) в окне, пока пользователь ожидает, вы можете использовать URI данных .

window.open('data:text/html,<h1>Loading...<%2Fh1>');
Jayphelps
источник
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 06
2

Наблюдение за тем, что событие должно быть инициировано пользователем, помогло мне понять первую часть этого, но даже после этого Chrome и Firefox все еще блокировали новое окно. Вторая часть добавляла target = "_ blank" к ссылке, которая упоминалась в одном комментарии.

В итоге: вам нужно вызвать window.open из события, инициированного пользователем, в данном случае щелкнув ссылку, и эта ссылка должна иметь target = "_ blank".

В приведенном ниже примере ссылка использует 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');
});
Алексис Беллидо
источник
2
var url = window.open("", "_blank");
url.location = "url";

это сработало для меня.

Диего Санта-Крус Мендесу
источник
1

Я использую этот метод, чтобы избежать блокировки всплывающих окон в моем коде React. он также будет работать во всех других кодах javascript.

Когда вы выполняете асинхронный вызов по событию щелчка, просто сначала откройте пустое окно, а затем напишите URL-адрес в нем позже, когда асинхронный вызов завершится.

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

при успешном выполнении асинхронного вызова напишите следующее

popupWindow.document.write(resonse.url)
Табиш
источник