window.open 被浏览器拦截问题
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() ,这种情况是否会被阻止呢?
答案:
- 我们用Chrome浏览器来测试,当延迟 100 毫秒的时候,Chrome 会让窗口弹出,但是当延迟 2000 毫秒(即 2s)时这个操作会被阻止。经过多次试验,我发现这个临界值是 1000 毫秒。1000 毫秒的时候允许弹出框, 1001 毫秒的时候被阻止
在 Safari / Chrome / Firefox下测试,都是 1001 毫秒的时候被阻止
- 整体来说,Safari / Chrome / Firefox (桌面版) , 对于用户点击事件后的 window.open() 有 1s
的延迟容忍度,如果是由用户点击触发的 window.open() 代码前面,可以加上少量简单的逻辑代码来运行,但请控制在执行时间为 1s 内
标题可能会起到效果的解决方案
1.创建一个a标签,利用a标签跳转,能解决大多数浏览器兼容问题,但是这种方法写在ajax异步请求完成后调用无效
function open(url) {
var a = document.createElement("a"); //创建a标签
a.setAttribute("href", url);
a.setAttribute("target", "_blank");
document.body.appendChild(a);
a.click(); //执行当前对象
}
open(url);
2.模拟form表单提交,能解决大多数浏览器兼容问题,但是这种方法写在ajax异步请求完成后调用无效
var form = document.createElement('form');
form.action = 接口地址;
form.target = '_blank';
form.method = 'POST';
document.body.appendChild(form);
form.submit();
3.在ajax调用之前先打开窗口,然后再设置新窗口的url来达到跳转的效果,但是该方法如果ajax响应太慢,则会出现一个空白窗口,影响用户体验,所以建议给该新窗口增加提示“正在拼命加载中”,但是我觉得这个并不是最好的解决方案
//先在ajax函数之前打开新窗口,后再加载url
function () {
//打开一个不被拦截的新窗口
var win = window.open();
win.document.body.innerHTML="正在拼命加载中......";
$.ajax({
url: 'xxx',
success: function (url) {
//修改新窗口的url
win.location.href = url;
}
})
});
4.把ajax异步改成同步,该方法会阻塞浏览器运行导致卡顿,经过测试,就算改成同步,chrome还是会阻拦,Firefox不会阻拦
//先在ajax同步函数之后打开新窗口
function () {
$.ajax({
url: 'a.com',
async: false, // 同步,意味着执行该ajax完成后,后续代码才继续运行
success: function (url) {
}
});
//执行完ajax后再打开新窗口
window.open(url, "_blank");
});
5.把ajax执行完后,弹出一个弹出框提示用户,由用户确认点击打开,这个方法目前感觉是最友好的
jQuery方式
$('#btn').click(function () {
$.ajax({
url: 'xxx',
success: function (url) {
option.open({
icon: 3,
title: "支付",
btn: ['立即查看', '取消'],
content: "文件已经校验成功,请查看结果",
btn1: function (index) {
option.closeAll();
window.open("./page/......");
},
btn2: function (index) {
option.closeAll();
}
});
}
});
});
vue方式
open(url) {
this.$confirm('此操作将会打开新窗口, 是否继续?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
window.open(url);
}).catch(() => {
this.$message({
type: 'info',
message: '已取消打开新窗口!'
});
});
},
onlineReviewClickNew(id) {
// 设置遮罩层
const loading = this.$loading({
lock: true,
text: '正在加载',
spinner: 'el-icon-loading',
background: 'rgba(0, 0, 0, 0.7)'
});
let url = url;
fetch(url,{
method: "get",
headers: {
// 如果需要登录权限认证,请求头在这里添加
}
}).then((res) => res.blob())
.then(data => {
loading.close();
this.open(encodeURIComponent(window.URL.createObjectURL(data))});
}).catch(error => alert(error.message));
},
/ 此处模拟的是在线预览PDF,前台接收后台返回的流数据经过处理之后通过pdf.js插件在线打开