2010年已经到了,已经好久没写博客了,在新年的起始该在园子里说点东西了。
前段时间给公司做了一个类似QQ的Asp.net在线聊天程序,与服务器之间的通讯是通过前台页面的定时器到服务器上的临时消息目录中取得相关信息来实现的,消息结构XML,为了避免对服务器造成太大的压力就只开了一个定时器,也没敢多开,程序完成后由于测试条件限制只在少的可怜的几台机器上测试了一下,效果还算可以吧,目前能实现发送文字,图片,文件查看历史记录,网络硬盘等基本功能,由于聊天窗口是嵌套在公司主框架里面的所以得实现聊天主窗体和聊天窗体以及一些其他窗体之间指针的引用问题,避免某个聊天窗口被打开多次,或者聊天窗口而主窗口也不知道的问题,下面介绍下程序中用javascript实现的窗口机制:
看其他人的程序是很困难的,所以先介绍下例子实现的效果:首先创建一个MainFrm.htm窗体(启动窗体) ,用它打开a.htm窗口,a.htm窗体只能打开一个,在a.htm窗体中可以打开b.htm和c.htm,当然b.htm和c.htm窗口也只能打开一个,然后当MainFrm.htm关闭时让a.htm,b.hml和c.htm也跟着关闭,或者a.htm关闭时让b.htm和c.htm也关闭
1、MainFrm窗体
为了方便应用,我对数组方法进行扩展,添加了add,remove,clear三个方法
Array.prototype.add = function() {
var startLength = this .length;
for (var i = 0 ; i < arguments.length; i ++ )
this [startLength + i] = arguments[i];
return this .length;
};
}
if ( ! Array.prototype.remove) {
Array.prototype.remove = function(index) {
if (index >= 0 && index < this .length)
{
this .splice(index, 1 );
}
};
}
if ( ! Array.prototype.clear) {
Array.prototype.clear = function() {
this .splice( 0 , this .length);
};
}
定义一个存放注册窗口的缓存数组
var g_oWindowArray = new Array();
为子窗体提供注册函数,并定义一个删除注册函数通过窗体ID找到注册窗体的函数
function RegisterWindow()
{
for (var i = 0 ; i < arguments.length; i ++ )
{
var oWin = arguments[i];
g_oWindowArray.add(oWin);
}
}
// 删除注册窗口
function UnregisterWindow()
{
// 从数组中删除
for (var i = 0 ; i < arguments.length; i ++ )
{
var tmpOWin = arguments[i];
for (var i = 0 ;i < g_oWindowArray.length;i ++ )
{
if (g_oWindowArray[i] == tmpOWin)
{
tmpOWin.close();
g_oWindowArray.remove(i);
}
}
}
}
// 通过用户ID找到注册过的窗口对象
function FindRegisterWindowById(strID)
{
for (var i = 0 ;i < g_oWindowArray.length;i ++ )
{
var oWin = g_oWindowArray[i];
if (oWin.GetFrmID() == strID)
{
return oWin;
}
}
return null ;
}
每个子窗体都必须实现的接口函数,这里只提供一个返回窗体标示ID的函数和取得MainFrm窗体指针的函数
function GetFrmID()
{
return "" ;
}
// 取得主窗体指针
function GetOpener()
{
return window;
}
当主窗体关闭时,关闭所有子窗体,主窗体关闭时执行的函数
window.onunload = function()
{
try
{
for (var i = 0 ;i < g_oWindowArray.length;i ++ )
{
var oWin = g_oWindowArray[i];
if (oWin)
oWin.parent.close();
}
}
catch (e)
{
alert( " 窗口注销时出错! " + e.message + " \n\n 错误说明 : " + e.description + e.message);
window.close();
}
}
打开a.htm
function ShowMain()
{
var oWin = FindRegisterWindowById( " aFrm " );
if (oWin == null )
{
var strURL = ' a.htm ' ;
var oWin = window.open(strURL);
}
else
oWin.focus();
return oWin;
}
MainFrm的Html代码
< input type = " button " value = " 打开窗体 " style = " height:50px;width:100px " onclick = " ShowMain(); " />
</ body >
2、a.htm窗体
a.htm中首先要实现MainFrm窗口定义的接口,由于要实现能关闭b.htm和c.htm所以包括了一个数组的add扩展方法(没有将数组扩展写成js文件)和一个窗口关闭时执行的方法,当然的包括窗口的注册了,代码不一一介绍,页面整体代码如下:
< script >
// 数组方法扩展
if ( ! Array.prototype.add) {
Array.prototype.add = function() {
var startLength = this .length;
for (var i = 0 ; i < arguments.length; i ++ )
this [startLength + i] = arguments[i];
return this .length;
};
}
var winOpener = window.opener.GetOpener();
var g_ChildWinArr = new Array();
/// //接口定义方法部分 /// /
// 取得当前窗体ID
function GetFrmID()
{
return " aFrm " ;
}
// 取得主窗体指针
function GetOpener()
{
return winOpener;
}
//
// 关闭窗口时候取消注册
window.onunload = function()
{
try
{
winOpener.UnregisterWindow(window);
for (var i = 0 ;i - g_ChildWinArr.length;i ++ )
{
var oWin = winOpener.FindRegisterWindowById(g_ChildWinArr[i]);
if (oWin != null )
{
winOpener.UnregisterWindow(oWin);
}
}
}
catch (e)
{}
}
// 向主页面注册窗体对象
winOpener.RegisterWindow(window);
function ShowOneFrm(strURL,strName)
{
try
{
var oWin = winOpener.FindRegisterWindowById(strName);
if (oWin == null )
{
oWin = window.open(strURL);
g_ChildWinArr.add(strName);
}
else
oWin.focus();
}
catch (e)
{
alert(strName + " 窗口消息注册过程中出错! " + e.message + " \n\n 错误说明 : " + e.description + e.message);
}
}
</ script >
< body >
< input type = " button " value = " 打开a窗体 " style = " height:25px;width:50px " onclick = " ShowOneFrm('c.htm','cFrm'); " />< br />
< input type = " button " value = " 打开b窗体 " style = " height:25px;width:50px " onclick = " ShowOneFrm('b.htm','bFrm'); " />
</ body >
</ html >
3、b.htm和c.htm窗体
这两个窗体的不用实现再关闭它的子窗体了所以不包含一些数组扩展函数和窗体关闭执行的函数等,只实现窗口注册和接口定义就行了
b.htm代码如下:
< script >
var winOpener = window.opener.GetOpener();
/// //接口定义方法部分 /// /
// 取得当前窗体ID
function GetFrmID()
{
return " bFrm " ;
}
// 取得主窗体指针
function GetOpener()
{
return winOpener;
}
// 向主页面注册窗体对象
winOpener.RegisterWindow(window);
// 注销窗体
window.onunload = function()
{
try
{
winOpener.UnregisterWindow(window);
}
catch (e)
{}
}
</ script >
< body >
< p > 我是B窗体 </ p >
</ body >
</ html >
c.htm代码如下:
< script >
var winOpener = window.opener.GetOpener();
/// //接口定义方法部分 /// /
// 取得当前窗体ID
function GetFrmID()
{
return " cFrm " ;
}
// 取得主窗体指针
function GetOpener()
{
return winOpener;
}
// 向主页面注册窗体对象
winOpener.RegisterWindow(window);
// 注销窗体
window.onunload = function()
{
try
{
winOpener.UnregisterWindow(window);
}
catch (e)
{}
}
</ script >
< body >
< p > 我是A窗体 </ p >
</ body >
</ html >
好了以上就是javascript 实现窗口注册的机制了,如果用于Web聊天的话就要多定义几个接口方法了,比如说:GetChatUserID()(获得当前聊天用户ID)、OnMessage(strMessageID,strMessageXML)(聊天窗口获得消息后的事件)等,不过我感觉要是网速过慢或者登录人过多的时候有可能会出现窗口的注册出现问题,这些就只能通过对错误的捕捉然后重新打开来实现了。
附件: