刷新后检索子窗口引用

时间:2010-11-02 17:31:32

标签: javascript dom html5

我有 HTML5离线应用(即没有服务器端组件/代码)。

它基本上有两个窗口(父窗口和子窗口)。但是,在某些情况下,我需要以编程方式刷新父窗口。发生这种情况时,它会丢失对子节点的引用,并且子节点对window.opener的引用不再有效。所以我的想法是我将序列化子窗口并将其存储在localStorage中。然后,当父母刷新时,它可以从localStorage中获取窗口引用,并仍然与孩子进行交互。

问题是这不起作用(根据我之前的问题Stringify DOMWindow object)。我无法像任何其他对象一样序列化DOM窗口。

那么我怎样才能让我新刷新的窗口获取对其前任孩子的引用呢?

修改:强调这是一个离线应用。没有服务器端组件。

我还应该补充一点,我需要刷新父级的原因是检查应用程序更新(缓存清单中的更改)。由于父是加载的应用程序中的第一个页面,它基本上管理缓存(事实上,在Safari中,如果在任何缓存过程中关闭此窗口,则整个浏览器崩溃)。所以“父”本质上是“用户加载的第一页”。 这意味着我不能在框架中拥有“父”,因为最顶层的窗口将管理缓存,并且需要刷新才能查找更新。实际上,似乎我可以使用frame方法,因为刷新应用程序中的任何页面都会触发更新检查。虽然很麻烦。

5 个答案:

答案 0 :(得分:12)

您可以通过以下技巧获得子窗口的引用。

newWin = window.open("", "child_window_name", "width=...");
if (newWin.location.href === "about:blank") {
    newWin = window.open("a.html", "child_window_name", "width=...");
} else {
    // We've already obtained the reference.
    // However, IE and FireFox won't put focus on an already opened window.
    // So we have to do that explicitly:
    newWin.focus();
}

请注意,您必须拥有固定的子窗口名称才能使此技巧有效。

示例网址: http://josephj.com/lab/2011/window-open-reconnect/demo.html

答案 1 :(得分:1)

见这里:http://www.w3.org/TR/html5/offline.html#dom-appcache-update

applicationCache.addEventListener("updateready", function() {
  applicationCache.swapCache();
  //now reload the body html
}, false);
setInterval(60000, applicationCache.update);//check for updates every minute

(每次下载新版本时都会触发updateready

答案 2 :(得分:0)

听起来像一个非常复杂的解决方案。为什么不将父窗口的内容放在不可见的iframe(即没有边框的iframe)中,只刷新框架?

这将允许您将引用保存在顶部文档中的框架和子窗口,两者都可以访问它。

答案 3 :(得分:0)

你可以在开场白上打电话告诉它重新加载并重新打开弹出页面吗?

e.g。

//in popup
window.opener.doReload('popup_page_name.html');
window.close();

//in opener
function doReload(popupURL){
  setSomeFormField(popupURL);
  someForm.submit();
}

然后在您的服务器端代码中,如果您有弹出窗口设置,请添加代码以重新启动它。

答案 4 :(得分:0)

我使用Window.postMessage实现了此方案,该方案启用了Window对象之间的跨域通信。它支持:https://caniuse.com/#feat=mdn-api_window_postmessage

在父与子Window对象之间建立通信的基本工作示例

在父应用中,

var childWindow = window.open(CHILD_URL);
setTimeout(() => { // postMessage on some browsers may need setTimout
  childWindow.postMessage( // STEP 1
     "INITIATE_CONNECTION", // message
     CHILD_URL // targetOrigin
  );
}, 500)

function receiveMessageFromChild(event) {
  if (event.origin === CHILD_URL) { // we should always check with the event.origin
    if (event.source) {
      if (event.data === "CONNECTION_SUCCESSFUL") {
        setTimeout(() => {
            event.source.postMessage( // STEP 3 and STEP 7
                "SEND_SOME_DATA_TO_CHILD",
                CHILD_URL);
        }, 500);
      }
      // other messages handling from child
    }
  }
}

if (window.addEventListener) {
  window.addEventListener("message", receiveMessageFromChild, false);
} else if (window.attachEvent) { // for IE
  window.attachEvent("onmessage", receiveMessageFromChild);
}

在子应用中,

function receiveMessageFromParent(event) {
  if (event.origin === PARENT_URL) { // we should always check with the event.origin
    var parentWindow = window.opener || event.source;
    if (parentWindow) {
      if (event.data === "INITIATE_CONNECTION" || event.data === "RE_NITIATE_CONNECTION") { // "RE_NITIATE_CONNECTION" msg from parent when parent is refreshed
         setTimeout(() => {
            parentWindow.postMessage( // STEP 2
                "CONNECTION_SUCCESSFUL",
                PARENT_URL);
         }, 500);
      }
      // other messages handling from parent
    }
  }
}

if (window.addEventListener) {
  window.addEventListener("message", receiveMessageFromParent, false);
} else if (window.attachEvent) { // for IE
  window.attachEvent("onmessage", receiveMessageFromParent);
}

要处理父窗口刷新并在刷新后对子窗口引用进行检索,请在上述代码中进行以下更改,

在父应用中,

document.body.onunload = () => { // before refreshing parent, this function will be called
  if (childWindow) {
    setTimeout(() => {
      childWindow.postMessage( // STEP 4
        "PARENT_REFRESHING",
        CHILD_URL
      );
    }, 500);
  }
};

function receiveMessageFromChild(event) {
  // ... above mentioned code in the parent app for this function
  .
  .
  .
  // other messages handling from child
  if (event.data === "PARENT_REFRESHED") {
    setTimeout(() => {
      event.source.postMessage( // STEP 6 - this event.source is a child window reference
        "RE_NITIATE_CONNECTION",
        CHILD_URL
      );
    }, 500);
  }
}

在子应用中,

function receiveMessageFromParent(event) {
  // ... above mentioned code in the child app for this function
  .
  .
  .
  // other messages handling from parent
  if (event.data === "PARENT_REFRESHING") {
    setTimeout(() => {
      event.source.postMessage( // STEP 5
        "PARENT_REFRESHED",
        CHILD_URL
      );
    }, 500);
  }
}

在上面的示例中,请参考步骤1至7。STEP 6是刷新父窗口时的子窗口引用。