使用window.open
前,需要先知道一个概念:Pop-up blocker(弹窗拦截)
Pop-up blocker(弹窗拦截)
目前,主流浏览器都有弹窗拦截机制,目的是为了阻止网站在非用户操作(如点击操作)时恶意弹出窗口(如弹窗广告、打开新窗口等),影响用户体验。
基于这个目的,浏览器会在用户操作时,允许同步打开弹窗;但对于异步打开弹窗操作,浏览器会判断从用户进行操作到打开弹窗的时间间隔,如果时间间隔超过它允许的时间值,就会启动拦截
参考文档:What are pop-ups
时机
由上述可知,使用window.open
的时机,应该是在用户操作(如点击操作)时同步调用
// 会被拦截
window.open('https://javascript.info');
// 不会被拦截
button.onclick = () => {
window.open('https://javascript.info');
};
时间
当异步使用window.open
时,就需要考虑与用户进行操作的间隔时间,不同浏览器允许的间隔时间不同,我们以FireFox为例
// 会被拦截
button.onclick = () => {
// 间隔3s打开会被拦截
setTimeout(() => window.open('http://google.com'), 3000);
};
// 不会被拦截
button.onclick = () => {
// 间隔2s打开不会被拦截
setTimeout(() => window.open('http://google.com'), 2000);
};
在不同浏览器中实际测试时间间隔为:
Chrome:小于5s(不包括5s)
FireFox:小于3s(不包括3s)
Edge:小于5s(不包括5s)
Safari:小于1s(不包括1s)
参考文档:Popups and window methods
其他方式打开新窗口
网上也搜到一些使用其他方式打开新窗口的方法,但经过实际测试,在异步打开新窗口的情况下,只要超过了浏览器拦截机制允许的间隔时间,也同样会被拦截。
Chrome中测试测试代码如下:
代码语言:javascript复制// a标签形式
const windowOpenBlank = (src) => {
console.log('a标签')
let a = document.querySelector('#window-open-blank-a') as HTMLLinkElement
if (!a) {
a = document.createElement('a')
a.target = '_blank'
a.style.cssText = 'display: none'
document.body.append(a)
}
a.href = src;
a.click();
}
// form表单形式
const windowOpenByForm = (src) => {
console.log('form submit')
let $form = document.querySelector('#window-open-blank-form') as HTMLFormElement
if (!$form) {
$form = document.createElement('form')
$form.method = 'GET'
$form.target = '_blank'
$form.style.cssText = 'display: none'
document.body.append($form)
}
$form.action = src
$form.submit()
}
let count = 0
const testOpen = (link) => {
count
// 同步
if (count === 1) {
// 允许打开
console.log('window.open方式同步打开')
window.open(link, '_blank')
} else if (count === 2) {
// 允许打开
console.log('form表单方式同步打开')
windowOpenByForm(link)
} else if (count === 3) {
// 允许打开
console.log('a标签方式同步打开')
windowOpenBlank(link)
return
}
// 异步
setTimeout(() => {
if (count === 4) {
// 被拦截
console.log('window.open方式异步打开')
window.open(link, '_blank')
} else if (count === 5) {
// 被拦截
console.log('form表单方式异步打开')
windowOpenByForm(link)
} else if (count === 6) {
// 被拦截
console.log('a标签方式异步打开')
windowOpenBlank(link)
} else if (count === 7){
// 允许跳转
console.log('window.location.href 异步跳转')
window.location.href = link
}
}, 5000)
}
异步方案
1. 使用window.location.href
通过上例发现,window.location.href
是允许进行异步操作的,实际测试将setTimeout
间隔时间设为1分钟也是不会被拦截的,所以,如果在只能异步操作,但是又得跳转链接的地方,建议使用window.location.href
,比如下载附件等操作
2. 引导弹窗
数据异步请求完成之后,弹出一个引导弹窗,用户点击确认按钮之后使用window.open直接跳转
弹窗广告插件
浏览器一般都会有一些第三方的弹窗广告拦截插件,网上能找的大概原理如下:
- 针对特定弹窗广告的selector,插件通过css设置
display: none;
隐藏弹窗广告 - 有的广告是通过cookie控制的,插件会注入cookie进行隐藏弹窗广告
- 有的插件允许自定义一些过滤规则
从现有查到的资料来看,异步调用window.open
被拦截是浏览器自带的机制,和是否使用广告插件无关