JavaScript:如何确保window.open返回相同的窗口,如果已经打开?

4

我正在开发一个基于Web的应用程序,其中需要打开弹出窗口。我使用window.open()方法打开弹出窗口,就像这样:

window.open(url, "popupWin");

其中的URL是我想让弹出窗口导航到的网址。问题是,如果我在多个标签页中执行window.open()(使用相同或不同的网址),至少在Chrome浏览器中,它可能/可能不会给你之前打开的同一个窗口。这种行为是不一致的,我的意思是,它应该每次都为我提供新的窗口,或者每次都为我提供先前打开的窗口。

我需要为整个域持久化同一个弹出窗口。如何实现?


1
你做不到。一个弹出窗口只能从打开它的选项卡中访问。 - Cerbrus
1
你确定吗?我认为它可以从同一来源访问。我猜不一致性取决于窗口的内容。如果内容与打开它的脚本以及尝试访问它的下一个脚本具有相同的来源,则应该保持不变。否则,将打开一个新窗口。检查控制台是否出现访问被拒绝的情况。 - mplungjan
1
如果弹出窗口对象引用不会出现在另一个选项卡上,那么如何从相同的来源访问它? - smnbbrv
嗨@mplungjan,感谢您的回复。实际上,我将代码导出到一个包含类似函数的模块的单独JS文件中以打开窗口。因此,在不同的选项卡上执行相同的代码。但是,有时候,当您在新标签页中打开新的URL(例如google.com),然后在另一个新标签页中打开自己的URL时,它会在Chrome上打破模式,并打开一个新窗口。 - Prakhar Mishra
2个回答

2
看起来有一个方向可走,或者至少可以尝试一下。
它完全依赖于 `localStorage`,这使得您可以在单个域内的标签之间共享知识。
我提供的代码尚未运行(只是一个方向),因此不要期望从按原样运行中获得太多效果。
它的功能是:通过 URL 将弹出窗口保存在 `localStorage` 中,当您尝试使用相同的 URL 打开新的弹出窗口时,它将不会这样做。如果您不想通过 URL 进行区分,则更简单:在 localStorage 中存储布尔值而不是对象。
但它没有实现但应该实现的:
1. 它应该监听弹出窗口的 `onunload`(关闭)事件,并相应地重置 `localStorage` 信息。对您最好的方法就是将 `localStorage` 的布尔值设为 `false`。 2. 它应该监听当前标签页的 `onunload`(重新加载、关闭)事件,并根据您的逻辑进行相应的重置。据我理解,最好的方法就是检查这个标签页是否是该域中的最后一个标签页(您也可以使用 localStorage 来进行这个操作,例如在每个新标签页上添加其标识符(例如创建时间戳)并在关闭标签页时销毁它),如果是,则将您的 localStorage 布尔值设为 `false`。
我认为这就足以解决问题了。最后,附上一个小片段代码:
// get the localstorage url map
function getOpenPopups() {
  var obj = localStorage.getItem('mypopups');

  return obj ? JSON.parse(obj) : {};
}

// set the localstorage url map
function setOpenPopups(object) {
  localStorage.setItem('mypopups', JSON.stringify(object))
}

// open the popup
function popup(url, title) {
  var popups = getOpenPopups();

  // check whether popup with this url is already open
  // if not then set it and open the popup
  if (!popups[url]) {
    popups[url] = true;

        setOpenPopups(popups);

    return window.open('abc', 'cde');
  }
  else {
    return false;
  }
}

jsFiddle


嗨@smnbbrv,感谢您的回答。实际上,我真正想做的是每当我调用“popup”函数时都有一个指向弹出窗口的引用,就像这样:https://jsfiddle.net/PrakharMishra/gp5k3evx/1/。 - Prakhar Mishra
1
@PrakharMishra 很抱歉,提出的方法是你唯一能做的。你无法获得对弹出窗口的引用,因为它属于另一个标签页/窗口/线程。你也不能在localStorage中存储引用。但你仍然可以从任何标签页与弹出窗口通信:只需将通知推送到localStorage中,并在另一侧的超时循环/间隔中读取它们。我知道,这不是最简单的方法,但我不确定你还能选择其他方法。 - smnbbrv

0
w3c文档中,我们可以看到window.open()返回一个对新创建的窗口的引用,或者如果调用失败则返回null。这意味着我们可以将其保存在内存中,并检查该窗口的closed标志。
var newWindow = window.open('/some/path', 'TestWindow');
// ...
if (!newWindow.closed) {

}

请注意,如果存在以下名称的窗口,则页面将在同一窗口中加载,而不会打开新窗口。 您还可以在官方文档中找到其他name参数的变体,例如_blank、_self、_top、_parent。

你好 @oleg-meleshko,有没有办法在多个/不同的选项卡中共享它?或者让它在重定向后仍然存在? - Prakhar Mishra
您可以在任何打开的窗口中使用 window.name 获取当前窗口名称。有了它,您可以使用一些单一的服务器/客户端存储来保持特定窗口状态的信息。 - oleh.meleshko

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