window.open() 某些情况会被浏览器阻止弹出窗口及解决办法

时间:2024-02-16 20:18:46

  window.open() 的作用是创建一个新的浏览器窗口用来打开相关的资源,这是一个原生的 Javascript API 接口。

  有关 window.open() 的基本使用可以参考 mozilla 提供的  API 文档:window.open 。

  大部分现代的浏览器(泛指 Chrome / Firefox / IE 10+ / Safari)都默认开启了阻止弹出窗口的策略,原因是 window.open 被广告商滥用,严重影响用户的使用。这个阻止弹出窗口的操作,并不是直接封杀 windw.open(),而是会根据用户的行为来判断这次 window.open() 是否属于流氓操作。

  如果是由用户触发的动作所引起的 window.open 就不会被浏览器所阻止,比如写在 onclick 这些事件 handler 里的,但如果是代码自己触发的就会被阻止。

  但是问题来了,如果是用户点击后,我们的程序需要运行一些代码然后才执行 window.open() ,这种情况是否会被阻止呢? 


  对于这种情况,我们来做个简单的例子,就是点击按钮之后将 window.open() 延迟一下,看看浏览器们有什么反应。

  当延迟 100 毫秒的时候,Chrome 会让窗口弹出,但是当延迟 2000 毫秒(即 2s )时这个操作会被阻止。经过多次试验,我发现这个临界值是 1000 毫秒。1000 毫秒的时候允许弹出框, 1001 毫秒的时候被阻止。

  大家可以通过修改代码中的延迟值来试。这个临界值,在 Safari / Chrome / Firefox (都是 for Mac) 下测试,均通过,都是 1001 毫秒的时候被阻止。

  结果拿到 IE 11 下测试,发现就算是 1 毫秒都会被阻止。

  我们先撇开 IE 的差异,我尝试把 setTimeout 转换成一些逻辑的代码放在 window.open() 前面。
  

  整体来说,Safari / Chrome / Firefox (桌面版) , 对于用户点击事件后的 window.open() 有 1s 的延迟容忍度。

  返回来测试了下 IE 11 的表现,发现:

  setTimeout 内的 window.open() 一律都被阻止,哪怕只是延迟 1毫秒
  对于逻辑运算的延迟则有比较大的容忍度,至少 3s 内依然被放行(没有再继续测试下去)
  然后顺便测试了下 Safari for iPad 8.0 的情况,发现:

  根据用户的设置(设置 -> Safari -> 阻止弹出窗口),无差别阻止或允许窗口的弹出窗。
  如果用户去掉了阻止弹出窗口的选项,那么无论是由用户点击的还是程序自行触发的,通通会弹出一个下的窗口询问用户是否要打开新的窗口。
  弄完之后得出的小结是:

  如果是由用户点击触发的 window.open() 代码前面,可以加上少量简单的逻辑代码来运行,但请控制在执行时间为 1s 内。
  不过由于各种原因,我们的 window.open() 会经常性的被阻止掉,虽说浏览器本身有对这个阻止事件做通知,但是由于用户是白痴的我们最好也在界面上做一些通知告知用户。我们可以利用 window.open () 的 return 值来判断 window.open 的执行情况,window.open 的返回值是一个打开的新窗口对象的引用, 如果 window.open 的操作被阻止,那么它的返回值就是 undefined 。

 我们知道了出现这种问题的原因,下面就给大家介绍几种解决办法:

  1.表单提交的方式

var form = document.createElement(\'form\');
    form.action = \'www.baidu.com?id=1\';
    form.target = \'_blank\';

    form.method = \'POST\';

document.body.appendChild(form);
form.submit();

   这种方式,如果需要传递参数时,需要使用 POST 方法, 默认的 GET 方法无法传递参数。也就是新页面的url中没有参数部分。

另外,Ajax下载文件时也是用form 表单来模拟下载。

2.直接将打开窗口操作放在按钮/链接的onclick事件中

<a href="javascript:void(0)" onclick="window.open(url)"></a>

3.延迟这个打开操作

setTimeout(\'window.open(url);\', 500); // 延迟时间不能太短 否则也会被拦截

4.通过JS打开新窗口会被拦截,换一种实现方式

var tempwindow=window.open(\'_blank\'); // 先打开页面
tempwindow.location=\'http://www.baidu.com\'; // 后更改页面地址