Уникайте блокаторів спливаючих вікон браузера


172

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

Як я можу запобігти блокуванню спливаючих вікон, створених або блокуючими спливаючих вікон різних браузерів, window.openабо window.showModalDialogблокувати їх?


11
Навіть якби це було можливо (я не знаю), якщо люди використовують блокуючі спливаючих вікон, ви повинні це поважати. Більшість браузерів відображає повідомлення, коли сайт намагався відкрити спливаюче вікно, щоб вони все ще могли бачити його, якщо хочуть. Ви можете помітити на своєму веб-сайті зауваження, що деякий вміст відкривається у спливаючому вікні, і користувач повинен дозволити це, щоб продовжити.
Фелікс Клінг

5
Найкраща практика виглядала б так: 1) Робіть це успішно 2) Закрийте свої вікна та заблокуйте двері та кришку від страху перед зібранням натовпу засмучених веб-меценатів 3) Покаяйтеся, видаліть спливаюче бюста-буста та поважайте ваша аудиторія.
Алекс Макп

Алекс і Фелікс, я оновив питання. Я не буду використовувати знання для зла :). Дякую!
Пабло Фернандес

9
Я хотів би додати, що обхід блокатора спливаючих вікон, можливо, насправді намагається покращити роботу користувачів. На прикладі, над яким я зараз працюю, ми використовуємо додаток Javascript (заснований на ExtJS) і ми намагаємось дозволити користувачам платити за допомогою PayPal. Ми надаємо їм кнопку, яку вони можуть натиснути, щоб запустити paypal у новому вікні, але певні версії IE блокують її як спливаюче вікно (навіть якщо це натискання кнопки). Якщо вони тепер увімкнули спливаюче вікно, екран перезавантажиться, і як додаток JavaScript, ми втратимо стан вікна, і вони повинні почати заново. Так справді: проблема в тому, що IE є німим.
NateDSaint

1
@FelixKling Так, це можливо. Виробники браузерів вже думали про це. Відкрити спливаюче вікно добре, наскільки є наміри користувача (сигналізується користувачем, натискаючи посилання або кнопку). Блокатори спливаючих вікон повинні дотримуватися намірів користувача. Якщо блокувальник спливаючих вікон IE цього не робить, винен блокатор спливаючих вікон. Користувачі використовують блокуючі спливаючих вікон для запобігання відкриттю скриптів за бажанням, а не для блокування спливаючих вікон, які вони самі намагалися відкрити (натиснувши кнопку або посилання).
Штійн де Вітт

Відповіді:


286

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


2
Цікаво, що спливаючі вікна, ініційовані через подію зміни, пов'язану з елементом вибору, будуть заблоковані (у Chrome, а не FF), навіть незважаючи на те, що ця подія ініціюється прямою діями користувача, як натисканням. Хоча якщо вони прив'язані до введення, вони дозволені. Дивно.
ccnokes

6
Ніхто не сказав, що браузер відповідає послідовності. : P
dthorpe

8
Завдяки експериментам я мав зрозуміти, що глибина стека не має нічого спільного з блокувальником спливаючих вікон. Він фактично перевіряє, чи викликається window.open протягом 1 секунди після дії користувача чи ні. Тестували в Chrome 46 та Firefox 42.
Mesqalito

Час очікування на 1 секунду можна обійти в обох веб-переглядачах, дозволяючи на невизначений проміжок часу використовувати відповідь @ tj-crowder на цій сторінці . Укажіть URL-адресу, яку ви телефонуєте через ajax, будь-який php (або будь-який інший), який використовує сон ( ) протягом певного часу, перш ніж він поверне відповідь. Веб-переглядач зависне, поки він 'завантажує' сторінку .., а потім запустить спливаюче вікно, коли отримає відповідь. Однак у Chrome ви повинні додати попередження () прямо перед ajax (), щоб цей трюк спрацював.
фанфари

184

На основі Jason Sebring «S дуже корисну пораду , і на речі , покриті тут і там , я знайшов ідеальне рішення для мого випадку:

Псевдо-код із фрагментами 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Біт допомагає для MAILTO Перенаправлення для роботи на мобільних пристроях, до речі.

Ваш досвід? Будь-який спосіб покращити це?


1
? так що робити, якщо це не від дій користувача у браузері? Для мого прикладу, після того, як користувач засвідчить автентифікацію на сервері, він повинен відкрити нову вкладку
Don Cheadle

@mmcrae цього не роблять. Що б ви не мали наміру зробити, є кращий спосіб, ніж спливаюче вікно. В іншому випадку є ймовірність, що я ніколи не захочу бачити ваш сайт. Сьогоднішні браузери переконують, що ви цього не можете робити - див. Відповідь @dthorpe .
Швейцарський містер

5
Whatever it is you intend to do, there is a better way than a popup windowЛол? Непарне узагальнення. Клієнт бажає, щоб сторінка, на якій він зареєструвалась автентифікацією, залишалася відкритою, а новий сайт / цільова сторінка після аутентифікації відкриється на новій вкладці. Так, не моя ідея чудового користувальницького досвіду ... але це здається розумним
Дон Чейдл

@mmcrae. Сядьте і подумайте, серйозно. Обіцяю вам, що ви знайдете "дію користувача" в описаному вами сценарії. Вся суть моєї відповіді полягає в тому, що ви створюєте спливаюче вікно, коли у вас є дія користувача, а потім заповнюєте його вмістом пізніше. Підказка для вашого випадку: користувач звертається до "автентифікувати" -> створити спливаюче вікно (порожнє); таймер увімкнено, або відповідь сервера повернулася або що завгодно -> заповнити вміст у спливаючому вікні.
Швейцарський містер

3
Корисна порада, якщо запит Ajax не вдасться, зателефонуйте, importantStuff.closeщоб закрити нову вкладку та надіслати повідомлення на початковій сторінці.
Гуска

24

Крім того, швейцарський пост Mister, в моєму випадку window.open був запущений всередині обіцянки, яка включила блокувальник спливаючих вікон, моє рішення було: у angular:

$scope.gotClick = function(){

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

    }
  );
};

Служба браузера:

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

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

ось так можна відкрити нову вкладку, використовуючи відповідь на обіцянку, а не викликаючи блокувальник спливаючих вікон.


1
Це призвело до мого рішення! Де я створив змінну, що містить відкриту вкладку, а потім заповнив URL після завантаження даних. Дякую. const tab = window.open(); observable.subscribe(dataUrl => tab.location.href = dataUrl);
jonas

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

Рішення @Alejandro Vales jonas працюватиме лише в тому випадку, якщо код запуститься від події onClick або будь-якої взаємодії з користувачем. Коли ви намагаєтесь відкрити нову вкладку через windows.закрити обіцянку, тайм-аут, підписатися ... браузер вважає, що це маніпуляція для користувача, тому рішенням є створити екземпляр перед тим, як ввести обіцянку, усередині вас просто зміниться href, як Jonas зробив
Девід

@David Дуже дякую !!! Мені не трапилося відповіді .thenна відповідь, і тому я так заплутався: / SRY ...
Алехандро Валес

@David Це чудово! Працює як шарм. Якби я міг вас турбувати ще одним питанням - чи знаєте ви, як зробити цю роботу і в Edge? Натискання на правий ресурс дуже допомогло б ...
dzenesiz

21

Як хороша практика, я думаю, що це гарна ідея перевірити, чи не було заблоковано спливаюче вікно, і вжити заходів у випадку. Потрібно знати, що 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 поверне нульове значення. Так функція поверне помилкову.

Як приклад, уявіть виклик цієї функції безпосередньо з будь-якого посилання на target="_blank": якщо спливаюче вікно буде успішно відкрито, повернення falseзаблокує дію посилання, інакше, якщо спливаюче вікно заблоковано, повернення trueдозволить поведінці за замовчуванням (відкрити нове вікно _blank) та продовжити .

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

Таким чином у вас буде спливаюче вікно, якщо воно працює, і вікно _ порожнє, якщо ні.

Якщо спливаюче вікно не відкриється, ви можете:

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

Дякую. Працювали!
Bcktr

8

від API oauth JavaScript від Google:

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

Дивіться область, де він читає:

Налаштування автентифікації

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

Я б здогадався, що це стосується реальної відповіді вище в тому, як вона пояснює, якщо є негайна відповідь, це не вимкне спливаючу тривогу. "Gapi.auth.init" робить це так, що api відбувається негайно.

Практичне застосування

Я зробив мікросервіс аутентифікації з відкритим кодом, використовуючи паспорт вузла на npm та різні пакети паспортів для кожного постачальника. Я використовував стандартний підхід до перенаправлення до третьої сторони, надаючи йому URL-адресу переадресації, щоб повернутися. Це було програмно, тому я міг мати різні місця для переадресації назад при вході / реєстрації та на певних сторінках.

github.com/sebringj/athu

passportjs.org


3

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

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


2
Це просто не працює для людей, у яких увімкнено функцію блокування спливаючих вікон
Алехандро Валес

що таке url? це не присвоєно.
shinriyo

@shinriyo URL - це посилання на будь-яку сторінку, до якої ви хочете отримати доступ, наприкладhttp://example.com
pomobc

@AlejandroVales У мене включений блокувальник спливаючих вікон, і він працює. Проблема полягає в тому, що window.open()не можна відкрити нове вікно програмно, і якщо нам потрібно, ця відповідь є одним із варіантів. За допомогою newTabзмінної, на яку ми посилаємось, window.open()і пізніше ми можемо її зателефонувати, вставити потрібну urlнам, в моєму випадку URL-адресу певної крапки, і нова вкладка буде відкрита з введеною URL-адресою.
stanimirsp

0

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

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

3
не працює для мене в Chrome 62. Спливаюче вікно (сторінка) блокується.
сєрмакович

1
Так, ти маєш рацію - я також визнав це непослідовним. Я зробив свій дзвінок api синхронним
користувач3479425

-8

Найпростіший спосіб позбутися цього:

  1. Не використовуйте document.open ().
  2. Замість цього використовуйте this.document.location.href = location; де місце - це URL-адреса для завантаження

Наприклад:

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

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

Це дуже добре працювало для мене. Ура


2
Що робити із відкриттям URL-адреси на новій вкладці?
3 правила
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.