Избегайте блокировщиков всплывающих окон браузера

Я разрабатываю поток аутентификации OAuth исключительно на JavaScript и хочу показать пользователю окно "Предоставить доступ" во всплывающем окне, но оно блокируется.

Как я могу предотвратить всплывающие окна, созданные либо window.open или же window.showModalDialog от блокировки блокировщиками всплывающих окон в разных браузерах?

12 ответов

Решение

Общее правило заключается в том, что блокировщики всплывающих окон будут задействованы, если window.open или подобное вызывается из JavaScript, который не вызывается прямым действием пользователя. То есть можно позвонить window.open в ответ на нажатие кнопки без попадания блокировщика всплывающих окон, но если вы добавите тот же код в событие таймера, он будет заблокирован. Глубина цепочки вызовов также является фактором - некоторые старые браузеры смотрят только на непосредственного абонента, новые браузеры могут немного откатить назад, чтобы увидеть, был ли вызывающий абонент щелчком мыши и т. Д. Держите его как можно более мелким, чтобы избежать блокировщиков всплывающих окон.

Основываясь на очень полезном совете Jason Sebring и на материалах, освещенных здесь и там, я нашел идеальное решение для моего случая:

Псевдокод с фрагментами Javascript:

  1. немедленно создать пустое всплывающее окно на действие пользователя

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

    Необязательно: добавьте некоторое "ожидающее" информационное сообщение. Примеры:

    а) Внешняя HTML-страница: замените вышеуказанную строку на

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

    б) Текст: добавьте следующую строку ниже приведенной выше:

    importantStuff.document.write('Loading preview...');
    
  2. заполните его содержимым, когда будете готовы (например, когда будет возвращен вызов AJAX)

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

Обогатить призыв к window.open с любыми дополнительными опциями, которые вам нужны.

Я на самом деле использую это решение для перенаправления почты, и оно работает во всех моих браузерах (Windows 7, Android). _blank бит помогает перенаправлению почты на мобильный, кстати.

Твой опыт? Есть ли способ улучшить это?

Как хорошая практика, я думаю, что это хорошая идея, чтобы проверить, было ли заблокировано всплывающее окно и принять меры в случае. Вы должны знать, что window.open имеет возвращаемое значение, и это значение может быть нулевым, если действие не выполнено. Например, в следующем коде:

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

если всплывающее окно заблокировано, window.open вернет ноль. Так что функция вернет false.

Например, представьте, что вы вызываете эту функцию напрямую из любой ссылки с target="_blank": если всплывающее окно успешно открыто, возвращение false заблокирует действие ссылки, иначе, если всплывающее окно заблокировано, возвращая true оставит поведение по умолчанию (откроет новое окно _blank) и продолжит.

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

Таким образом, у вас будет всплывающее окно, если оно работает, и окно _blank, если нет.

Если всплывающее окно не открывается, вы можете:

  • откройте пустое окно, как в примере, и продолжайте
  • открыть поддельное всплывающее окно (iframe внутри страницы)
  • сообщить пользователю ("пожалуйста, разрешите всплывающие окна для этого сайта")
  • откройте пустое окно и затем сообщите пользователю и т. д.

В дополнение к сообщению Swiss Mister, в моем случае window.open был запущен в обещании, которое включало блокировку всплывающих окон, мое решение было: in angular:

$scope.gotClick = function(){

  var myNewTab = browserService.openNewTab();
  someService.getUrl().then(
    function(res){
        browserService.updateLocation(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;
}

таким образом, вы можете открыть новую вкладку, используя ответ на обещание и не вызывая блокировщик всплывающих окон.

из JavaScript API Google:

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

Смотрите область, где написано:

Настройка аутентификации

Реализация клиента OAuth 2.0 использует всплывающее окно, чтобы предложить пользователю войти в систему и одобрить приложение. Первый вызов gapi.auth.authorize может вызвать блокировку всплывающих окон, так как он косвенно открывает всплывающее окно. Чтобы запретить блокировку всплывающих окон при вызовах аутентификации, вызовите gapi.auth.init(callback) при загрузке клиента. Предоставленный обратный вызов будет выполнен, когда библиотека будет готова сделать аутентификационные вызовы.

Я бы предположил, что это связано с реальным ответом выше, в том, как он объясняет, если есть немедленный ответ, он не отключит всплывающую тревогу. "Gapi.auth.init" делает это так, что API происходит немедленно.

Практическое применение

Я сделал микросервис аутентификации с открытым исходным кодом, используя паспорт узла на npm и различные паспортные пакеты для каждого провайдера. Я использовал стандартный подход перенаправления к третьей стороне, предоставляя ей URL перенаправления для возврата. Это было программно, так что я мог иметь различные места для перенаправления обратно, если вход / регистрация и на определенных страницах.

https://github.com/sebringj/athu

http://passportjs.org/

Я пробовал несколько решений, но это единственное, которое действительно работает для меня во всех браузерах

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

Мой вариант использования: в моем приложении для реагирования при нажатии пользователем выполняется вызов API на бэкэнд. На основе ответа открывается новая вкладка с ответом api, добавленным в качестве параметров к URL-адресу новой вкладки (в том же домене).

Единственное предостережение в моем варианте использования заключается в том, что для получения ответа API требуется больше 1 секунды. Следовательно, блокировщик всплывающих окон появляется (если он активен) при открытии URL-адреса в новой вкладке.

Чтобы обойти описанную выше проблему, вот пример кода,

var new_tab=window.open()
axios.get('http://backend-api').then(response=>{
    const url="http://someurl"+"?response"
    new_tab.location.href=url;
}).catch(error=>{
    //catch error
})

Сводка: создайте пустую вкладку (как в строке 1 выше), и когда вызов API завершится, вы можете заполнить вкладку URL-адресом и пропустить блокировщик всплывающих окон.

@здесь я обнаружил, что он отлично работает во всех браузерах

      window.open(URL) || window.location.assign(URL)

Просто используйте window.location.href = yourUrlили URL с target='_blank'

window.open()имеет слишком много проблем, если это более одной секунды от действия пользователя, многие браузеры рассматривают его как всплывающее окно и блокируют его

Мне удалось это с помощью функции setTimeOut.

      setTimeOut(function(){
  window.location.replace("https://www.google.com/");
}, 1000)

✅✅✅✅✅

Я не хотел создавать новую страницу, если обратный вызов не был успешно возвращен, поэтому я сделал это для имитации клика пользователя:

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

Самый простой способ избавиться от этого, который работал для меня очень хорошо -

  1. Не используйте document.open().
  2. Вместо этого используйте this.document.location.href = location; где location это URL для загрузки

Пример:

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

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

Это работает очень хорошо. ура

Другие вопросы по тегам