JavaScript回调函数中的window.open

19

window.open() 被主线程调用时,默认情况下会打开一个新标签页。

但是,在 Opera 16 和 Google Chrome 29 中,每次都会打开一个新窗口。

<input type="button" value="Open" onclick="cb1()">

<script type="text/javascript">  
function cb1() {
    setTimeout(wo, 1000); //simple async
}

function wo()
{
   var a = window.open("http://google.com", "w2");
   a.focus();
}
</script>

这是我对使用JavaScript在新标签页中打开URL(而不是新窗口)的答案。

我该如何在当前浏览器标签页中打开链接(按照浏览器默认设置)?


这种行为发生在哪个浏览器中? - shanet
@Gurminder Singh,所有浏览器配置都正确(默认为选项卡而不是阻止弹出窗口)。如果我直接调用wo() <input type="button" value="Open" onclick="wo()">,一切都很好。 - zardoz
你尝试过这个代码吗?_var a = window.open(url, 'blank'); - Gurminder Singh
@Gurminder Singh,我需要这里的名称(仅一个选项卡)。 - zardoz
我已经亲自尝试了您的代码,它会打开一个选项卡而不是窗口。 - Gurminder Singh
显示剩余4条评论
5个回答

20

我们遇到了同样的问题并在SO上寻找答案。我们发现适用于我们情况的方法是:

该问题与浏览器弹出窗口阻止程序化窗口打开有关。浏览器允许来自主线程上实际用户点击的窗口打开。同样地,如果您在主线程上调用window.open,它也将起作用。根据此回答,如果您正在使用Ajax调用并希望在成功后打开窗口,则需要设置 async: false ,因为这会使所有内容保持在主线程上。

我们无法像那样控制我们的Ajax调用,但发现另一种解决方案也可行,因为原因相同。警告:这有点不规范,请根据您的约束判断是否合适。通过不同的答案中的评论,您可以在调用 setTimeout 之前打开窗口,然后在延迟函数中更新它。有几种方法可以做到这一点。要么在打开窗口时保留对窗口的引用 w = window.open ... 并设置 w.location ;要么在延迟函数中使用目标打开,window.open('', 'target_name'),然后在该目标中打开,window.open('your-url','target_name'),并依赖于浏览器保持引用。

当然,如果用户的设置是在新窗口中打开链接,则无法更改该设置,但这对OP不是问题。


2
对于那些需要更详细代码的人,请查看这篇博客文章:http://theandystratton.com/2012/how-to-bypass-google-chromes-javascript-popup-blocker - Chetan Shenoy

6

像其他帖子提到的那样,最好的方法是先打开窗口,然后在回调或异步函数后设置其位置。

<input type="button" value="Open" onclick="cb1()">

<script type="text/javascript">

function cb1() {
  var w = window.open('', 'w2');
  setTimeout(function () {
    wo(w);
  }, 1000); //simple async
}

function wo(w)
{
  w.location = "http://google.com";
  w.focus();
}
</script>

如果您使用async await,您也会遇到相同的问题。同样的解决方案仍然适用。

public async openWindow(): Promise<void> {
    const w = window.open('', '_blank');
    const url = await getUrlAsync();
    w.location = url;    
}

进一步的增强是在初始页面上打开窗口,通过加载URL或向该页面编写一些HTML来提供一些快速反馈。
public async openWindow(): Promise<void> {
    const w = window.open('', '_blank');
    w.document.write("<html><head></head><body>Please wait while we redirect you</body></html>");
    w.document.close();
    const url = await getUrlAsync();
    w.location = url;    
}

这将防止用户在等待解析您的URL的时间内看到空白的标签页/窗口。

1

这个方法甚至更加“hackier”但是...

如果你在 window.open 的外面包裹一个 console.log ,那么它会起作用。

console.log(window.open('https://someurl', '_blank'))


0
如果一个新窗口作为新标签页或新实例打开,这取决于用户设置。

原帖作者表示,在某些情况下,它会在新标签页中打开,在其他情况下则会在新窗口中打开,因此他遇到的问题显然与用户设置无关。 - Yogh

0
我曾经使用过 NestjsVue3,但是我用下面的代码解决了问题。 我只是从后端发送到 localhost:8080 的令牌进行了切片,并将其设置为本地存储,然后将用户重定向到下一页。这样用户就可以使用这个token进行授权。 Vue 3。 这种方法已经解决了问题。你可以改进它,使它变得更好。 因为我在后端使用了 OAuth google-passport 而不是 firebase,所以我是这样做的。
<script>

methods: {
     googleLogin() {
      const win = window.open(
        "http://localhost:3000",
        "windowname1",
        "width=800, height=600"
      );
      const validateToken = (token) => {
        localStorage.setItem("token", token);
        this.$router.push("/GeneralPage");
        window.clearInterval(pollTimer);
        clearInterval(pollTimer);
        win.close();
      };
      const pollTimer = window.setInterval(async () => {
        try {
          let url = win.document.URL;
          let token = url.slice(22, url.length);
          if (token !== "") {
            localStorage.setItem("token", token);
            this.$router.push("/GeneralPage");
            clearInterval(pollTimer);
            win.close();
            validateToken(token);
            return;
          }
          return;
        } catch (e) {}
      }, 1000);
    },
}
</script>


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接