Avoid browser popup blockers

2018-12-31 15:25发布

I'm developing an OAuth authentication flow purely in JavaScript and I want to show the user the "grant access" window in a popup, but it gets blocked.

How can I prevent pop up windows created by either window.open or window.showModalDialog from being blocked by the different browsers' pop-up blockers?

8条回答
孤独总比滥情好
2楼-- · 2018-12-31 15:59

The general rule is that popup blockers will engage if window.open or similar is invoked from javascript that is not invoked by direct user action. That is, you can call window.open in response to a button click without getting hit by the popup blocker, but if you put the same code in a timer event it will be blocked. Depth of call chain is also a factor - some older browsers only look at the immediate caller, newer browsers can backtrack a little to see if the caller's caller was a mouse click etc. Keep it as shallow as you can to avoid the popup blockers.

查看更多
低头抚发
3楼-- · 2018-12-31 16:01

As a good practice I think it is a good idea to test if a popup was blocked and take action in case. You need to know that window.open has a return value, and that value may be null if the action failed. For example, in the following code:

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

if the popup is blocked, window.open will return null. So the function will return false.

As an example, imagine calling this function directly from any link with target="_blank": if the popup is successfully opened, returning false will block the link action, else if the popup is blocked, returning true will let the default behavior (open new _blank window) and go on.

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

This way you will have a popup if it works, and a _blank window if not.

If the popup does not open, you can:

  • open a blank window like in the example and go on
  • open a fake popup (an iframe inside the page)
  • inform the user ("please allow popups for this site")
  • open a blank window and then inform the user etc..
查看更多
ら面具成の殇う
4楼-- · 2018-12-31 16:06

Based on Jason Sebring's very useful tip, and on the stuff covered here and there, I found a perfect solution for my case:

Pseudo code with Javascript snippets:

  1. immediately create a blank popup on user action

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

    Optional: add some "waiting" info message. Examples:

    a) An external HTML page: replace the above line with

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

    b) Text: add the following line below the above one:

    importantStuff.document.write('Loading preview...');
    
  2. fill it with content when ready (when the AJAX call is returned, for instance)

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

Enrich the call to window.open with whatever additional options you need.

I actually use this solution for a mailto redirection, and it works on all my browsers (windows 7, Android). The _blank bit helps for the mailto redirection to work on mobile, btw.

Your experience? Any way to improve this?

查看更多
闭嘴吧你
5楼-- · 2018-12-31 16:07

I didn't want to make the new page unless the callback returned successfully, so I did this to simulate the user click:

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);
  });
}
查看更多
像晚风撩人
6楼-- · 2018-12-31 16:08

I tried multiple solutions, but his is the only one that actually worked for me in all the browsers

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

查看更多
君临天下
7楼-- · 2018-12-31 16:09

In addition Swiss Mister post, in my case the window.open was launched inside a promise, which turned the popup blocker on, my solution was: 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;
}

this is how you can open a new tab using the promise response and not invoking the popup blocker.

查看更多
登录 后发表回答