65.9K
CodeProject 正在变化。 阅读更多。
Home

JavaScript 关闭子窗口

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.73/5 (9投票s)

2008年9月12日

CPOL

2分钟阅读

viewsIcon

106572

downloadIcon

892

当父窗口关闭时,如何使用 JavaScript 关闭打开的子窗口。

当父窗口关闭时关闭子窗口

动机

在将应用程序从 Windows 迁移到 Web 时,我注意到 Windows 窗体中某些功能需要移植到 Web 窗体中。不幸的是,有时实现这些功能比预期的要困难。

目标

由于面向对象,我希望在客户端有一个即插即用的解决方案来关闭子窗口。经过一番研究,我了解到调用 window.open 会返回一个 window 对象,稍后可以对其调用 close。需要解决的问题是如何在打开时存储每个窗口对象,以及如何检测浏览器关闭以关闭子窗口。

注意:有很多文章介绍如何在 JavaScript 中创建对象,这超出了本文的范围。

代码

持久化窗口句柄

首先,持久化 open 函数调用返回的窗口对象。我通过将其作为对象内的私有 Array 存储来实现。

function windowController(){
  //Note: The absence of “this” indicates private
  var loadedWindows = new Array()
  …..
} //Note: Yes, in JavaScript an object
  // is declared similar to a function.

封装 window.open

现在我有一个不错的数组,我需要一个公共方法来包装 window.open 函数,以捕获返回的对象并将其添加到我的数组中。

this.popUpWindow = function(wndUrl, wndName, wndWidth, wndHeight){
var windObj = null;
try
{
  //set default width 
  if(typeof wndWidth == 'undefined') wndWidth=500;
  //set default height
  if(typeof wndHeight == 'undefined') wndHeight=250;
  windObj = window.open(wndUrl, 
    //misc options to open a window, again mostly optional 
    wndName, 'toolbar=0,menubar=0,resizable=0,location=0,
    directories=0,width='+wndWidth+',height='+wndHeight); 
  windObj.registerID = wndName; //this is the key to the window
  loadedWindows[loadedWindows.length] = windObj;
  //add the window to our collection.
}
catch(ex) { 
  alert('WindowController.popUpWindow: ' + 
        'Exception occured, message: ' + ex.message)
} //oops, looks like we are cross domain scripting.
return windObj;
}

进一步增强封装

由于我正在包装 window.open,我决定只允许打开每个句柄 ID 的单个实例,方法是检查 ID 是否已加载到每个窗口句柄中,如果存在,则简单地调用 focus(这与 Windows 窗体中的预期行为类似)。

this.popUpWindow = function(wndUrl, wndName, wndWidth, wndHeight){
  var windObj = null;
  try{
    windObj = findWindow(wndName);
    if (windObj != null)
    {
      windObj.focus();
    }
    else
    {
     ......
    }

其中 findWindow 函数只是遍历数组,如果未找到则返回 null

function findWindow(winHandle){
  for (var i=0; i< loadedWindows.length; i++){
  if (loadedWindows[i].closed == true){
    loadedWindows.splice(i,1);
    i--;
  }
  else{
    if (loadedWindows[i].registerID == winHandle)
      return loadedWindows[i];
    }
  }
  return null;
}

整合

最后,我需要一种方法来知道浏览器何时关闭,以便关闭所有子窗口。当然,与其它浏览器相比,IE 具有不同的事件注册方式,因此我创建了一个通用方法来实现这一点。

function WireEvent(elem,target,func){
  if (elem.addEventListener)
    elem.addEventListener(target, func, false); //FF
  else if (elem.attachEvent)
    elem.attachEvent(target, func); //IE
  }
  WireEvent(window,'onunload',_windowController.closeAllWindows);

其中 onunload 函数的处理方式如下

this.closeAllWindows = function(){
  for(var x = 0; x < loadedWindows.length; x++){
    try{
      loadedWindows[x].close();
    }
    catch(err) {
      alert('WindowController.closeAllWindows: ' + 
            'Exception occured, message: ' + err.message)
    }
  } //oops, cross domain scripting or window already closed etc...
}

看起来一切就绪了,我需要的最后一件事是初始化对象的能力,以便从代码中访问它,因此我在 js 文件的顶部添加了调用,如下所示……

var _windowController = new windowController();

使用对象

现在,如果包含该文件,我们就可以访问窗口控制器,只要通过此对象打开所有子窗口,我们就可以确定它们在浏览器退出时会关闭,只要我们不在跨域环境中即可。

_windowController.popUpWindow('ChildForm.aspx', 'ChildForm');
© . All rights reserved.