网站搜索

javascript - 捕获子窗口的全局 window 对象,考虑刷新情况


嗨,网络上的朋友们,快速场景说明:我有一个应用程序使用子窗口来提供工具,通过 window.open('/tools', '_blank') 打开。它返回一个 window 对象,我可以给它添加事件监听器,但当用户点击刷新按钮,或者窗口执行重定向(我的窗口会这样,因为它有一个搜索功能)时,window 对象会被销毁,或者至少我无法使用它来获取当前窗口。所以我的应用程序认为窗口已经关闭,即使它实际上并没有关闭。

当我需要使用window对象在主应用程序和窗口之间交换消息时,这就成了一个问题。如果用户更改了window对象,这将不再起作用。我只是想知道是否有更好的方法来做到这一点。

显然,我可以在应用程序中使用 HTML 内置提示,但出于整洁的原因,我尽量避免这样做,这样用户就可以使用他们操作系统的窗口系统来更方便地使用应用程序。

就代码示例而言,没有太多可以展示的,我有两个脚本,一个在主窗口上,一个在工具窗口上,

主要

$("#btn").on('change', function() {
  const windowRef: Window | null = window.open('/tools', '_blank');
  if (windowRef)
    $(windowRef).on('load', function() {
      windowRef.connect = function() {
        // Initialise tools and functions here
      };
      $(windowRef).on('beforeunload', () => $("#btn").prop('checked', false));
    });
});

工具窗口

...
<body>
  <script defer>
    new Promise((ok, err) => 'connect' in window ? ok(window.connect()) : err());
  </script>
</body>

答案#1

问题不在于与子窗口的连接被破坏,因为在刷新或重定向时不会发生这种情况。你可以通过 windowRef.closed 来检查这一点。我的猜测是,你的初始化函数包含需要在刷新/重定向后重新应用的逻辑。使用以下代码:

windowRef.connect = function() {
   // Initialise tools and functions here
};

你为新打开的窗口定义了一个全局函数,随后该函数在新窗口中被调用。当页面刷新/重定向时,JavaScript 所做的所有临时更改都会丢失。这对于 windowRef.connect 来说是正确的,对于 $ (windowRef).on('load'; ...) 也是如此:

$("#btn").on('change', function() {
  const windowRef: Window | null = window.open('/tools', '_blank');
  if (windowRef)
    // The registration of this listener is lost when the subwindow is refreshed
    $(windowRef).on('load', function() {
      windowRef.connect = function() {
        // Initialise tools and functions here
      };
      $(windowRef).on('beforeunload', () => $("#btn").prop('checked', false));
    });
});

这意味着当子窗口被刷新时,来自子窗口的以下脚本:

...
<body>
  <script defer>
    new Promise((ok, err) => 'connect' in window ? ok(window.connect()) : err());
  </script>
</body>

永远不会有一个函数 window.connect,因为监听器不会再次被调用。你可以通过 window.opener 来解决这个初始化问题:

主窗口:

let windowRef: Window | null;
$("#btn").on('change', function() {
  windowRef = window.open('/tools', '_blank');
});
// has to be a global function accessible via window.initialize
function initialize() {
  // Initialise tools and functions here
  $(windowRef).on('beforeunload', () => $("#btn").prop('checked', false));
}

工具窗口:

// on load in the tool window will be called after redirect/refresh
$(window).on("load", () => {
  if(window.opener) {
    // Get main window, which opened the sub window and call initialize.
    window.opener.initialize();
  }
})