window.open(url, '\_blank')
可以打开新的窗口,但是在异步的时候使用就出现问题了
async myButtonClick(){
let url = await this.CopyData(this.data, val);
// after: 5000ms
if(url) {
window.open(url,'_blank');
像这种情况,就偶尔可以直接跳转,偶尔会被浏览器拦截:
这样很影响用户体验呀!!!
找解决办法
1. 没有用:通过创建a标签
在请求完成后 a.click(), 用来骗浏览器模拟用户点击。
async myButtonClick(){
let url = await this.CopyData(this.data, val);
if(url) {
var $a = $('<a>', { href: str, target: '_blank'});
this.$refs.themeMy.append($a);
$a.click();
// 这种情况并没有用,还是会被拦截
2. 没有用:调用链的深度也是一个因素
尽可能保持浅层以避免弹出窗口阻止程序。
// 之前
$('#myButton').click(function() {
this.getJson()
getJson() {
this.CopyData()
CopyData() {
let url = await this.CopyData(this.data, val);
window.open(url,'_blank');
// 更改
$('#myButton').click(async function() {
let url = await this.getJson()
window.open(url,'_blank');
// 这样浅了把,but 并没有什么用, 还是会拦截
也就是堆栈深度与弹出窗口阻止程序并没有任何关系。
3. 有用但不好用:提前 window.open
更改控制流以首先打开窗口(同步),然后执行 AJax 请求(异步),然后使用响应显示错误消息或执行重定向。
$('#myButton').click(async function() {
let newTab = window.open('');
let url = await this.getJson()
newTab..location.href = url;
从代码可知是提前给打开了新的空白的窗口,注意哦是空白的,用户需要在空白页傻等~ 等待重定向,也不知道那个小天才想出来的,我佩服 但实际是不敢这么用的。
1. window.open()的Api
以上就是网上的都没用,怎么办呢,我先去查查window.open()的Api,发现这个是有返回值的,如果调用失败,返回值会是 null
。我测试了一下,当拦截的时候确实返回值是空的。ok 现在拿到了第一个有用的是信息了,
通过 window.open()的Api ,我能知道什么情况下是没有跳转成功、失败返回值会是 null
2. 分析为什么偶尔拦截
既然是异步,我就用setTimeout()
进行模拟请求时长
myButtonClick(){
setTimeout(() => {
window.open('sdf', '_blank')
}, 6000)
发现当我设置成5秒的时候都会被拦截,当我设置成2秒的时候都会成功。
所以我猜测浏览器的弹窗机制的原因:
如果window.open
从 javascript 调用或类似的调用,过了规定的时间,就会判定为不是由直接用户操作调用,则弹出窗口阻止跳转。
已经知道了弹窗机制就是过了一定时间就会阻止,这是浏览器特意的安全机制,那我们就更多的从业务上入手吧。
1. 把默认跳转改为通过弹框询问用户是否进行跳转?
既然第一次点击的时候需要请求那么久,那我们可以在接收到值得时候,
在弹出一个步骤,来提示(询问)一下用户是否进行跳转或者一个“下一步”按钮。
async myButtonClick(){
let url = await this.CopyData(this.data, val);
this.openNewAlert(url)
// 显示弹窗
openNewAlert(url){
// 点击'是'的回调 window.open(url,'_blank');
// 点击'否'的回调 关闭弹窗
2. 提示用户被拦截了
通过 window.open()的Api ,我能知道什么情况下是没有跳转成功,所以可以对失败的时候进行一个提示。
async myButtonClick(){
let url = await this.CopyData(this.data, val);
if(url) {
let windowObjectReference = window.open(url,'_blank');
if(windowObjectReference == null) {
alert('页面跳转已被浏览器拦截');
3. 提示用户被拦截了, 并提供跳转
在上一个的基础上添加一个更友好的交互,来让用户点击跳转
// Message 为elment-ui的全局方法,如果使用其他ui组件可参考改造
if(windowObjectReference == null) {
Message({
type: 'warning',
customClass:'myherf',
dangerouslyUseHTMLString:true,
message: `页面跳转已被浏览器拦截,点击允许本次<a href=`+ str +` target='_blank' onclick="(function(){document.getElementsByClassName('myherf')[0].remove()})()">跳转</a>`,
duration: 0,
Stackoverflow:Avoid browser popup blockers
Stackoverflow:Bypass popup blocker on window.open when JQuery event.preventDefault() is set
Stackoverflow:Chrome window.open after ajax request acts like popup
天真的小郭
12.6k