现象
最近在做项目的时候碰到了使用window.open被浏览器拦截的情况,虽然在本地的环境可以对浏览器设置操作,但是对用户来说,不能要求用户都来通过拦截。
可以发现,当window.open为用户触发事件内部或者加载时,不会被拦截,一旦将弹出代码移动到ajax或者一段异步代码内部,马上就出现被拦截的表现了。
原因
一般情况下,如果直接在js中调用window.open()函数去打开一个新窗口,浏览器检测到的是非用户操作产生的新弹出窗口,就会对其进行阻止。因为浏览器认为这可能是一个广告,不是一个用户希望看到的页面。
window.open('//www.baidu.com', '_blank');
经过查阅资料,总结以下5个方案,目前采用的是方案2
-
方案一:而对于如下代码:
document.body.addEventListener('click' function() { window.open('//www.baidu.com, '_blank'); });
优点:所有浏览器都不会拦截
缺点:只要点击页面元素都会进行跳转,不是很友好 -
方案二:使用a标签替代,代码如下
const a = document.createElement('a'); a.href = location.origin+'adress' document.body.appendChild(a) a.click() document.body.removeChild(a)
优点:模拟a标签,利用a标签的href进行页面的跳转,兼容所有浏览器
缺点:需要创建a标签 -
表单提交的方式
const 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中 没有参数部分。
-
通过JS打开新窗口会被拦截,换一种实现方式(与5相似,5是放在异步执行之后在页面跳转)
const tempPage=window.open('_blank'); // 先打开一个空页面 tempPage.location='http://www.baidu.com'; //目标的页面地址
-
先弹出窗口,然后重定向
建议在打开第一个地址的时候给出一个类似‘当前页面正在加载中,请稍后…’的简单提示,可以避免打开两次真正的目标页面,让用户察觉到页面的重定向。
dom.addEventListener('click', function () { const tempPage = window.open('loading page'); ajax().done(function() { // 重定向到目标页面 tempPage.location.href = 'target url'; }); });