woocall:Ajax开发页面聊天系统

2007年发表于IT168  链接地址:http://publish.it168.com/2007/0702/20070702007901.shtml

不知大家有没有用过新浪的Woocall,如果没有用过也没有关系,现在就去试用一下http://Woocall.sina.com.cn,大家是不是感觉很酷,那么大家想不想自己开发一个,如果有这个打算的话,就随懒羊一起来吧。

    一、系统功能概述

本系统主要包括两个界面,一个是最小化时的界面(图一),另一个为聊天(还原)时的界面(图二)。

 

              图一                               图二

主要实现功能有:

1、  在线访客统计

2、  呢称修改功能

3、  信息发送功能

4、  信息接收功能

5、  聊天记录保存功能(IE)

测试环境:IE6.0  Firefox 2.0.0 .4

二、界面的实现

前台主要通过Div+Css实现,具体实现代码如下:

Pl.htm

<!DOCTYPE html PUBLIC "-//W 3C //DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">

<head>

<meta http-equiv="Content-Type" content="text/html; charset=gb2312" />

<title>懒羊页面聊天系统</title>

<link href="main.css" rel="stylesheet" type="text/css" />

<script src="xml.js"></script>

<script src="lanyangpl.js"></script>

</head>

<body>

<div class="top"><img src="images/t_1.gif" /><span>懒羊页面聊天系统</span><sapn class="tright"><img οnclick="changemax();" οnmοusemοve="this.src='images/max_1.gif'" οnmοuseοut="this.src='images/max.gif'" class="timg" src="images/max.gif" /><img class="timg" src="images/close.gif" οnclick="closeMsg();" οnmοusemοve="this.src='images/close_1.gif'" οnmοuseοut="this.src='images/close.gif'" /><img src="images/t_2.gif" /></span></div><div class="minmain" οnclick="changemax();"><span id ="minmain">开发:懒羊(杨剑)-系统正在启动……</span></div></div>

<div class="top"><img src="images/t_1.gif" /><span>懒羊页面聊天系统</span><sapn class="tright"><img οnclick="changemin();" οnmοusemοve="this.src='images/min_1.gif'" οnmοuseοut="this.src='images/min.gif'"  class="timg" src="images/min.gif" /><img class="timg" src="images/close.gif" οnclick="closeMsg();" οnmοusemοve="this.src='images/close_1.gif'" οnmοuseοut="this.src='images/close.gif'" /><img src="images/t_2.gif" /></span></div><div class="gn"><ul><li><input οnchange="document.getElementById('gm').disabled=false; document.getElementById('gm').src='images/gm.gif'" id="nc" name="nc" class="nc" type="text" /></li><li><input οnclick="modifyNc();" name="gm" id="gm" class="gm" type="image" src="images/gm_1.gif" disabled="true" /></li><li class="gnm" id="minmain">开发:懒羊(杨剑)</li><li class="gnr"><input οnmοusemοve="this.src='images/ltjl_1.gif'" οnmοuseοut="this.src='images/ltjl.gif'" οnclick="savechat();" id="ltjl" name="ltjl" type="image" src="images/ltjl.gif" /></li></ul></div><div id="tsinfo" class="tsinfo"><textarea readonly="readonly" id="tsinfomain" name="tsinfomain" class="tsinfomain">信息提示区|正在加载信息请稍候</textarea></div><div class="chat"><iframe id="chatmain" name="chatmain" src="chatmain.html" frameborder="1"></iframe></div><div class="fs"><ul><li><textarea οnkeydοwn="keypress();" id="fscontent" name="fscontent" class="fsmain">大家好!</textarea></li><li class="fsbtn" ><input οnclick="sendMessage();" οnmοusemοve="this.src='images/fs_1.gif'" οnmοuseοut="this.src='images/fs.gif'" id="fsbtn" name="fsbtn" type="image" src="images/fs.gif"/></li></ul></div></div>

</body>

</html>

Main.css

.top {width:300px;height:34px;text-align:left;font-size:14px;color:#FFFFFF;background:url(images/t_3.gif);}

.top img{cursor:hand;float:left;}

.top span{float:left;width:210px;margin-top:10px;}

.timg{margin-top:5px;margin-left:5px;}

.minmain{width:300px;text-align:center;font-size:12px;line-height:30px;height:30px;background:#eeeeee;cursor:hand}

.gn{width:300px;height:30px;background:#eeeeee;font-size:12px;text-align:left;}

.gn ul{margin:0;padding:0;list-style:none;}

.gn ul li{float:left;}

.nc{width:80px;height:21px;}

.gm{margin-top:5px;margin-left:3px;height:21px;}

.gnm{text-align:center;width:105px;line-height:30px;font-size:12px;float:left;}

.gnr{margin-top:5px;width:54px;}

.tsinfo{height:30px;background:#eeeeee;font-size:12px;width:300px;}

.tsinfomain{height:30px;background:#eeeeee;font-size:12px;width:295px;}

.chat{width:300px;background:#eeeeee;}

.chatmain{width:295px;height:200px;}

.fs{width:300px;background:#eeeeee;}

.fs ul{margin:0; list-style:none;padding:0;}

.fs ul li{float:left;}

.fsmain{background:url(images/fsbg.gif);width:230px;height:50px;}

.fsbtn{margin:5px 0px 0px 10px;}

#eMsg{z-index:99999;visibility: hidden; position: absolute;}

.chatroom{font-size:12px;}

.msg{font-size:12px;line-height:20px;}

.msgnc{float:left;font-size:12px;color:#FF0000;}

.msgcont{font-size:12px;}

pl.htm是为了方便大家阅读采用的页面,在系统中为了方便调用,将会将以上html文件转换为js脚本文件,并且将两个界面分别通过变量minstr与maxstr存储,这样有助于两个界面的切换。代码如下:

interface.js

var minstr="<div class=/"top/"><img src=/"images/t_1.gif/" /><span>懒羊页面聊天系统</span><sapn class=/"tright/"><img οnclick=/"changemax();/" οnmοusemοve=/"this.src='images/max_1.gif'/" οnmοuseοut=/"this.src='images/max.gif'/" class=/"timg/" src=/"images/max.gif/" /><img class=/"timg/" src=/"images/close.gif/" οnclick=/"closeMsg();/" οnmοusemοve=/"this.src='images/close_1.gif'/" οnmοuseοut=/"this.src='images/close.gif'/" /><img src=/"images/t_2.gif/" /></span></div><div class=/"minmain/" οnclick=/"changemax();/"><span id =/"minmain/">开发:懒羊(杨剑)-系统正在启动……</span></div></div>";

var maxstr="<div class=/"top/"><img src=/"images/t_1.gif/" /><span>懒羊页面聊天系统</span><sapn class=/"tright/"><img οnclick=/"changemin();/" οnmοusemοve=/"this.src='images/min_1.gif'/" οnmοuseοut=/"this.src='images/min.gif'/"  class=/"timg/" src=/"images/min.gif/" /><img class=/"timg/" src=/"images/close.gif/" οnclick=/"closeMsg();/" οnmοusemοve=/"this.src='images/close_1.gif'/" οnmοuseοut=/"this.src='images/close.gif'/" /><img src=/"images/t_2.gif/" /></span></div><div class=/"gn/"><ul><li><input οnchange=/"document.getElementById('gm').disabled=false; document.getElementById('gm').src='images/gm.gif'/" id=/"nc/" name=/"nc/" class=/"nc/" type=/"text/" /></li><li><input οnclick=/"modifyNc();/" name=/"gm/" id=/"gm/" class=/"gm/" type=/"image/" src=/"images/gm_1.gif/" disabled=/"true/" /></li><li class=/"gnm/" id=/"minmain/">开发:懒羊(杨剑)</li><li class=/"gnr/"><input οnmοusemοve=/"this.src='images/ltjl_1.gif'/" οnmοuseοut=/"this.src='images/ltjl.gif'/" οnclick=/"savechat();/" id=/"ltjl/" name=/"ltjl/" type=/"image/" src=/"images/ltjl.gif/" /></li></ul></div><div id=/"tsinfo/" class=/"tsinfo/"><textarea readonly=/"readonly/" id=/"tsinfomain/" name=/"tsinfomain/" class=/"tsinfomain/">信息提示区|正在加载信息请稍候</textarea></div><div class=/"chat/"><iframe id=/"chatmain/" name=/"chatmain/" src=/"chatmain.html/" frameborder=/"1/"></iframe></div><div class=/"fs/"><ul><li><textarea οnkeydοwn=/"keypress();/" id=/"fscontent/" name=/"fscontent/" class=/"fsmain/">大家好!</textarea></li><li class=/"fsbtn/" ><input οnclick=/"sendMessage();/" οnmοusemοve=/"this.src='images/fs_1.gif'/" οnmοuseοut=/"this.src='images/fs.gif'/" id=/"fsbtn/" name=/"fsbtn/" type=/"image/" src=/"images/fs.gif/"/></li></ul></div></div>";

[xss_clean]("<div id=/"eMsg/">"+minstr+"</div>");

 

三、界面效果及位置的实现

上图为模拟网页页面的效果图,首先我们先看看上面标号文字的具体含义:

1.     document.documentElement.clientWidth

网页可见宽度,包括间隙,但不包括边框与滚动条

2.     document.documentElement.clientHeight

网页可见高度,包括间隙,但不包括边框与滚动条

3.     document.documentElement.scrollLeft

横向滚动条离左边距的距离

4.     document.documentElement.scrollTop

纵向滚动条离上边距的距离

5.     页面聊天系统所显示的区域,主要参数

宽度:document.getElementById("页面聊天系统ID"). offsetWidth

高度:document.getElementById("页面聊天系统ID").offsetHeight

左边距:document.getElementById("页面聊天系统ID").style.left

上边距:document.getElementById("页面聊天系统ID").style.top

由于我们要将页面聊天系统定位在页面的右下角,因此我们要做如下的算法:

左边距:document.getElementById("页面聊天系统ID").style.left=(document.documentElement.clientWidth+ document.documentElement.scrollLeft- document.getElementById("页面聊天系统ID").offsetHeight)+ "px"

上边距:document.getElementById("页面聊天系统ID").style.top= (document.documentElement.clientHeight + document.documentElement.scrollTop

- document.getElementById("页面聊天系统ID").style.top)+"px"

当网页触发以下事件时必须对位置进行重新设置:

1.     _window.onresize

当窗口发生变化时触发

2._window.onscroll

         当窗口滚动条滚动条触发

     代码如下:

_window.onload = getMsg; //页面加载时触发

_window.onresize = resizeDiv; //页面大小发生变化时触发

window.οnscrοll= resizeDiv; //滚动条滚动时时触发

 

var divWidth,divHeight,docHeight,docWidth,objTimer,i = 0,nc,frompage,objTimerout,objTimeronline;

function getMsg()  //定位页面聊天系统位置

{

******//此处星号为下文所用到函数

    try{

    divHeight = parseInt(document.getElementById("eMsg").offsetHeight,10);

    divWidth = parseInt(document.getElementById("eMsg").offsetWidth,10);

    docWidth = document.documentElement.clientWidth;

    docHeight = document.documentElement.clientHeight;

    document.getElementById("eMsg").style.top =(parseInt(document.documentElement.scrollTop,10) + docHeight + 10)+"px";

    document.getElementById("eMsg").style.left =(parseInt(document.documentElement.scrollLeft,10) + docWidth - divWidth)+"px";

    document.getElementById("eMsg").style.visibility="visible" ;

    objTimer = window.setInterval("moveDiv()",10) ;  

    }

    catch(e){}

}

 

function resizeDiv()

{

    try{

    divHeight = parseInt(document.getElementById("eMsg").offsetHeight,10);

    divWidth = parseInt(document.getElementById("eMsg").offsetWidth,10);

document.getElementById("eMsg").style.top =(document.documentElement.clientHeight - divHeight + parseInt(document.documentElement.scrollTop,10))+"px";

   document.getElementById("eMsg").style.left = (parseInt(document.documentElement.scrollLeft,10) + document.documentElement.clientWidth - divWidth)+"px";

    }

    catch(e){}

}

function moveDiv()

{  try

    {

    if(parseInt(document.getElementById("eMsg").style.top,10) <= (docHeight - divHeight + parseInt(document.documentElement.scrollTop,10)))

    {

    window.clearInterval(objTimer);

    objTimer = window.setInterval("resizeDiv()",1);

    }

    divTop = (parseInt(document.getElementById("eMsg").style.top,10))+"px";

    document.getElementById("eMsg").style.top =( divTop - 1 )+"px";

    }

    catch(e){}

}

 

备注:

objTimer = window.setInterval("resizeDiv()",1)

含义:每隔1毫秒运行一次resizeDiv()函数

window.clearInterval(objTimer)

含义:停止setInterval所运行的函数

objTimeronline=window.setTimeout("OnlineNum()",2000) ;

含义:隔2000毫秒运行一次OnlineNum()函数

window.clearTimeout(objTimerout);

含义:停止运行OnlineNum()函数

是不是你会觉得这两个函数有点一样,其实不然。setInterval是每隔多少运行一次函数A,而setTimeout是隔了多少秒后运行一次函数A,而函数A中必须再一次指定运行函数A,当然你也可以再函数A中运行函数B,但setInterval却不可以。 我个人觉得setTimeout更自由、更随意。

四、Ajax原理

Ajax为“Asynchronous JavaScript + XML”的简称,主要是通过JavaScript对象中的XmlHttpRequest向服务器提出请求,并根据处理的结果更新页面。这样的更新不会使整个页面全部更新,而是根据用户的需要对某个区域进行局部更新,而且在更新的同时不影响其它区域的浏览。

以下为Ajax部分的源码,为了方便大家使用,只需明白如何调用即可,关于本节代码的详细介绍,在《asp+ajax打造无刷新新闻评论系统》一文中已经叙述过。

Xml.js

/*创建并返回XmlHttp对象开始*/

var xhr;

function getXHR()

{

     try {

            xhr=new ActiveXObject("Msxml2.XMLHTTP");

     } catch (e) {         

            try {

                   xhr=new ActiveXObject("Microsoft.XMLHTTP");

            } catch (e) {                

                   xhr=false;

            }

     }

     if(!xhr&&typeof XMLHttpRequest!='undefined')

     {

            xhr=new XMLHttpRequest();

     }    

    

     return xhr;

}

 

function openXHR(method,url,callback)

{

     getXHR();

     xhr.open(method,url);

     xhr.onreadystatechange=function()

     {

            if(xhr.readyState!=4)return;

            callback(xhr);       

     }

     xhr.send(null);

}

 

function loadXML(method,url,callback)

{

     getXHR();

     xhr.open(method,url);

     xhr.setRequestHeader("Content-Type","text/xml");

     xhr.setRequestHeader("Content-Type","GBK");

     xhr.onreadystatechange=function()

     {

            if(xhr.readyState!=4)return;

            callback(xhr);

     }

     xhr.send(null);

}

 

loadXML(“http方法”,”URL地址”,”function”)

function为loadXML成功调用后所返回的处理函数,本函数默认参数为xmlDOM

例:假使我们要请求一个list.asp页面,请求成功后返回setList(xmlDom),采用返回函数主要是为了方便移植与重复使用,我们可以根据不同的请求设置不同的返回处理,而不必要去考虑xmlHttp是如何实现的。

 

五、数据库规划

Chatroom表——存储聊天记录

字段名

id

nc

frompage

dateandtime

chatmsg

说明

编号

呢称

来源页

时间

聊天内容

类型

自动编号

文本

文本

日期/时间

文本

长度

 

20

50

 

200

 

Msg表——存储提示信息

字段名

id

msg

frompage

说明

编号

信息内容

来源页

类型

自动编号

文本

文本

长度

 

200

50

 

online表——存储当前在线访客

字段名

id

nc

frompage

说明

编号

呢称

来源页

类型

自动编号

文本

文本

长度

 

20

50

 

     六、系统登陆

     页面聊天系统是让在同一个页面上的网友可以相互聊天,而不是所有进入系统的网友,这就要求我们必须在进入系统时先对网页URL进行判别,其次是生成一个唯一的呢称,最后提交给服务器处理程序进行处理;为了兼容Firefox,我们还必须对浏览器进行判别,根据不同的浏览器作出不同的处理。

1、  来源页URL判别

frompage=_window.location.href;

2、  获得浏览器类型

    b=navigator.appName;

3、  根据当前时间生成呢称

function rndName()  //获得默认呢称

{

       var date=new Date();  //建立一个日期对象

       mo=String(date.getMonth());//获得当前月份

       d=String(date.getDate());//获得当前日期

       h=String(date.getHours());//获得当前小时

       mi=String(date.getMinutes());//获得当前分钟

       s=String(date.getSeconds());//获得当前秒数

 nc="ly"+mo+d+h+mi+s; //生成呢称

}

4、  提交服务器

function login()

{    

       loadXML("get","login.asp?frompage="+frompage+"a&b="+b+"&nc="+ nc+ "a",loginOk);

}

function loginOk()

{    

OnlineNum();

}

 

5、  服务器处理程序

Login.asp

<% Response.Charset="gb2312" %>

<% Session.CodePage=936 %>

<!--#include file="conn.asp"-->

<%

Response.addHeader "pragma", "no-cache"

Response.addHeader "cache-control", "private"

Response.CacheControl = "no-cache"

if instr(b,"Netscape") then  '如是Firefox则对编码进行转换,下同

frompage= StreamToStr(request("frompage"))

nc= StreamToStr(request("nc"))

else

nc=del1(request("nc"))

frompage=del1(request("frompage"))

end if

set rs=server.CreateObject("adodb.recordset") '如果服务器不存在此页与呢称,则添加

sql="select * from online where frompage='"&frompage&"' and nc='"&nc&"'"

rs.open sql,conn,1,3

if  rs.bof and rs.eof then

rs.addnew

rs("frompage")=frompage

rs("nc")=nc

rs.update

 

set rsx=server.CreateObject("adodb.recordset")   '添加提示信息

sql="select * from msg where frompage='"&frompage&"'"

rsx.open sql,conn,1,3

rsx.addnew

rsx("frompage")=frompage

rsx("msg")=nc&"进入系统"

rsx.update

rsx.close

 

end if

rs.close

set rs=nothing

conn.close

set conn=nothing

%>

七、在线访客统计

客户端:

function OnlineNum()

{

     if(objTimeronline)

     {

     loadXML("get","online.asp?frompage="+frompage+"a&b="+b,OnlineNumOk);

     }

     objTimeronline=window.setTimeout("OnlineNum()",2000) ;

}

    

function OnlineNumOk(xmlDom) 

{

     if(document.getElementById("minmain"))

     {

document.getElementById("minmain")[xss_clean]=xmlDom.responseText;

     }

     }

服务端程序:online.asp

<% Response.Charset="gb2312" %>

<% Session.CodePage=936 %>

<!--#include file="conn.asp"-->

<%

Response.addHeader "pragma", "no-cache"

Response.addHeader "cache-control", "private"

Response.CacheControl = "no-cache"

b=request("b")

if instr(b,"Netscape") then

frompage=StreamToStr(request("frompage"))

else

frompage=del1(request("frompage"))

end if

set rs=server.CreateObject("adodb.recordset")

sql="select * from online where frompage='"&frompage&"'"

rs.open sql,conn,1,3

if not rs.bof or not rs.eof then

onlinenum=rs.recordcount

end if

rs.close

set rs=nothing

conn.close

set conn=nothing

response.write("在线"&onlinenum&"人")

%>

 

八、呢称修改功能

为了聊天方便,有时系统自动生成的呢称并不能直观明了,这就要求我们对系统进行呢称修改,呢称修改必须注意的是当系统中存在同一呢称时,将会提示呢称重复,而且无法修改。

客户端:

function modifyNc()

{

     if(objTimeronline) window.clearTimeout( objTimeronline)

     var newnc=document.getElementById("nc").value

     loadXML("get","modifync.asp?frompage="+frompage+"a&b="+b+"&nc="+ nc+ "a&newnc="+newnc+"a",modifyNcOk);

     }

function modifyNcOk(xmlDom) 

{

     if(xmlDom.responseText=="提示:改名成功")

     {

     nc=document.getElementById("nc").value;

     }

     OnlineNum();

     document.getElementById("minmain")[xss_clean]=xmlDom.responseText;

}

服务器端:modifync.asp

<% Response.Charset="gb2312" %>

<% Session.CodePage=936 %>

<!--#include file="conn.asp"-->

<%

Response.addHeader "pragma", "no-cache"

Response.addHeader "cache-control", "private"

Response.CacheControl = "no-cache"

b=request("b")

if instr(b,"Netscape") then

nc=trim(StreamToStr(request("nc")))

newnc=trim(StreamToStr(request("newnc")))

frompage=trim(StreamToStr(request("frompage")))

else

nc=del1(trim(request("nc")))

newnc=del1(trim(request("newnc")))

frompage=del1(trim(request("frompage")))

end if

set rs=server.CreateObject("adodb.recordset")

sql="select * from online where frompage='"&frompage&"' and nc='"&newnc&"'"

rs.open sql,conn,1,1

if  rs.bof and rs.eof then

conn.execute "update online set nc='"&newnc&"' where nc='"&nc&"' and frompage='"&frompage&"'"

conn.execute "update chatroom set nc='"&newnc&"' where nc='"&nc&"' and frompage='"&frompage&"'"  '更新聊天记录中的呢称

session(newnc)=session(nc)  '控制获得旧呢称的聊天记录

set rsx=server.CreateObject("adodb.recordset")   '添加信息提示

sql="select * from msg where frompage='"&frompage&"'"

rsx.open sql,conn,1,3

rsx.addnew

rsx("frompage")=frompage

rsx("msg")=nc&"改名为"&newnc

rsx.update

rsx.close

response.Write("提示:改名成功")

else

response.Write("提示:呢称已存在")

end if

rs.close

set rs=nothing

conn.close

set conn=nothing

%>

 

九、信息发送功能

客户端:

function sendMessage() 

{

     var fscontent=document.getElementById("fscontent").value;

     if(fscontent=="")

     {

            alert("内容不可为空!");

            return false;

     }

     document.getElementById("minmain")[xss_clean]="正在发送…";

 

            document.getElementById("fscontent").value="";

loadXML("get","sendmessage.asp?frompage="+frompage+"a&nc="+ nc+ "a&b="+b+"&fscontent="+fscontent+"a",sendMessageOk);

}

function sendMessageOk(xmlDom) 

{

     document.getElementById("minmain")[xss_clean]=xmlDom.responseText;    

}

服务器端:sendMessage.asp

<% Response.Charset="gb2312" %>

<% Session.CodePage=936 %>

<!--#include file="conn.asp"-->

<%

Response.addHeader "pragma", "no-cache"

Response.addHeader "cache-control", "private"

Response.CacheControl = "no-cache"

b=request("b")

if instr(b,"Netscape") then

frompage=StreamToStr(trim(request("frompage")))

nc=StreamToStr(trim(request("nc")))

fscontent=StreamToStr(trim(request("fscontent")))

else

frompage=del1(trim(request("frompage")))

nc=del1(trim(request("nc")))

fscontent=del1(trim(request("fscontent")))

end if

set rs=server.CreateObject("adodb.recordset")

sql="select * from chatroom"

rs.open sql,conn,1,3

rs.addnew

rs("frompage")=frompage

rs("nc")=nc

rs("dateandtime")=now()

rs("chatmsg")=fscontent

rs.update

rs.close

set rs=nothing

response.Write("提示:发送成功!")

%>

 

为了方便发送信息,在输入信息的文本框中添加按键事件οnkeydοwn="keypress();"

function keypress()   //按键为alt+s

{          

      var keycode = event.keyCode?event.keyCode:event.which?event.which:event.charCode;

      if((keycode==83)&&(event.altKey)){

      sendMessage();}

}

十、信息接收功能

客户端:

function getChat()  //获得聊天信息

{

if(document.getElementById("chatmain").contentWindow.document.body)

{          loadXML("GET","getChat.asp?frompage="+frompage+"a&b="+b+"&nc="+ nc+ "a",getChatOk);

}

  objTimerout=window.setTimeout("getChat()",1000);

}

function getChatOk(xmlDom)

{

     var cont="";

     var chatinfo=xmlDom.responseXML.getElementsByTagName("chatinfo");      

     var len=chatinfo.length;

     for(var i=0;i<len;i++)

     {

            var nc=chatinfo[i].childNodes[0].firstChild.data;

            var msgcont=chatinfo[i].childNodes[1].firstChild.data;

            var msgdate=chatinfo[i].childNodes[2].firstChild.data;

      cont+="<div class=/"msg/"><div class=/"msgnc/">"+nc+":</div><div class=/"msgcont/">"+msgcont+" ["+msgdate+"]</div></div>";

     }

     if(document.getElementById("chatmain").contentWindow.document.body)

{          document.getElementById("chatmain").contentWindow.document.body[xss_clean]="<div id=/"authorInfo/" class=/"chatroom/"><font color=/"#ff0000/">欢迎使用懒羊页面聊天系统v1.0<br/>开发人:懒羊<br/>开发时间: 2007-6-22 <br/>------------------------------------<br/></font></div>"+cont;

     document.getElementById("chatmain").contentWindow.document.body.scrollTop=document.getElementById("chatmain").contentWindow.document.body.scrollHeight;

}

var msginfo=xmlDom.responseXML.getElementsByTagName("msginfo");

if(document.getElementById("tsinfomain")&&msginfo[0])

{  

document.getElementById("tsinfomain").value= msginfo[0].firstChild.data;

}

}

服务器端:getchat.asp

<% Response.Charset="gb2312" %>

<% Session.CodePage=936 %>

<!--#include file="conn.asp"-->

<%

b=request("b")

if instr(b,"Netscape") then

nc=StreamToStr(request("nc"))

frompage=StreamToStr(request("frompage"))

Response.write("<?xml version=""1.0"" encoding=""UTF-8""?>")

else

nc=del1(request("nc"))

frompage=del1(request("frompage"))

Response.write("<?xml version=""1.0"" encoding=""gb2312""?>")

end if

Response.ContentType = "text/XML"

Response.expires = 0

Response.expiresabsolute = Now() - 1

Response.addHeader "pragma", "no-cache"

Response.addHeader "cache-control", "private"

Response.CacheControl = "no-cache"

if session(nc)="" then

session(nc)=now()  '获得当前时间

end if

set rs=server.CreateObject("adodb.recordset")

sql="select * from chatroom where frompage='"&frompage&"' and datediff('s','"&session(nc)&"',dateandtime)>0"

rs.open sql,conn,1,1

if  not rs.bof or not rs.eof then

do while not rs.eof

content=content&"<chatinfo><nc>"&rs("nc")&"</nc><msgcont>"&rs("chatmsg")&"</msgcont><msgdate>"&formatdatetime(rs("dateandtime"),3)&"</msgdate></chatinfo>"

rs.movenext

loop

end if

rs.close

set rs=nothing

 

set rs=server.CreateObject("adodb.recordset")

sql="select * from msg where frompage='"&frompage&"' order by id desc"

rs.open sql,conn,1,1

if  not rs.bof or not rs.eof then

do while not rs.eof

msg=msg&rs("msg")&chr(13)

rs.movenext

loop

end if

rs.close

set rs=nothing

conn.close

set conn=nothing

response.Write("<lanyang>"&content&"<msginfo>"&msg&"</msginfo></lanyang>")

%>

 

注:

1、if session(nc)="" then  

session(nc)=now()  

end if

当访客进入系统后,获得的只是从访客开始向后的聊天信息,而并非所有信息,因此我们就必须对访客进入系统的时间进行存储,而且因为同一台电脑可以打开多个页面,我们必须保证每个页面存储时间的变量唯一,因此我们通过根据唯一的呢称来设定变量,但由于改名以后呢称发生变化,因此我们要将旧呢称的时间信息存储到新的呢称变量中,这样就可以保证我们前面聊天记录的不丢失。

2、服务器端文件为asp生成的xml文件,其中主要包括chatinfo与msginfo两个节点,前者节点用来显示聊天信息,而后者则为操作提示信息。

十一、系统退出

系统退出包括两种方式:一是关闭浏览器,二是关闭系统(系统右上角的小叉)。不管是那一种方式的退出都必须在退出后删除online表中的访问者信息。但两者也有所不同,关闭系统后网页还在运行某此函数,因此我们必须先停止这些函数,否则JS会提示找不到对象而出错。在服务器端我们会根据在线的人数进行不同的删除操作,当最后一位访问者退出系统时,我们将会删除关于这个页面的所有聊天信息及提示信息。

客户端:

window.οnunlοad=unloadpage; //此函数所处位置为前面第三节中代码星号位置

function closeMsg()

{

if(confirm("提示:关闭后通过刷页面再次打开!"))

{

document.getElementById("eMsg")[xss_clean]="";

document.getElementById("eMsg").style.display="none";

if(objTimer) window.clearInterval(objTimer);

unloadpage();

}

}

 

function unloadpage()  //退出程序所执行的函数

{

     loadXML("get","quit.asp?frompage="+frompage+"a&b="+b+"&nc="+ nc+ "a",blankfunction);

     if(objTimerout) window.clearTimeout( objTimerout)

     if(objTimeronline) window.clearTimeout( objTimeronline)

     }

function blankfunction(xmlDom)  //空函数

{//空函数}

 

服务器端:quit.asp

<% Response.Charset="gb2312" %>

<% Session.CodePage=936 %>

<!--#include file="conn.asp"-->

<%

b=request("b")

if instr(b,"Netscape") then

frompage=StreamToStr(trim(request("frompage")))

nc=StreamToStr(trim(request("nc")))

else

frompage=del1(request("frompage"))

nc=del1(request("nc"))

end if

set rs=server.CreateObject("adodb.recordset")

sql="select * from online where frompage='"&frompage&"' and nc='"&nc&"'"

rs.open sql,conn,1,3

if not rs.bof or not rs.eof then

rs.delete

rs.update

end if

rs.close

set rs=nothing

 

set rsx=server.CreateObject("adodb.recordset")   '添加信息提示

sql="select * from msg where frompage='"&frompage&"'"

rsx.open sql,conn,1,3

rsx.addnew

rsx("frompage")=frompage

rsx("msg")=nc&"退出系统"

rsx.update

rsx.close

 

set rs=server.CreateObject("adodb.recordset")

sql="select * from online where frompage='"&frompage&"'"

rs.open sql,conn,1,1

if not rs.bof or not rs.eof then

onlinenum=rs.recordcount

end if

rs.close

set rs=nothing

 

if onlinenum=0 then

conn.execute "delete from chatroom where frompage='"&frompage&"'"

conn.execute "delete from msg where frompage='"&frompage&"'"

end if

conn.close

set conn=nothing

response.write("提示:成功退出!")

%>

 

十二、保存记录

function savechat() //保存记录

{

     if(window.clipboardData)

   {

             window.clipboardData.clearData();

             window.clipboardData.setData("Text", txt);

                    alert("提示:已经将记录复制到剪贴板,请通过Ctrl+v或粘贴到其它编辑器中。");

    } else

      {

            alert("此浏览器不支持剪贴板复制!");

            return false;

}

}

    十三、还原按钮与最小化按钮

最小化按钮:

function changemin() 

{

document.getElementById("eMsg")[xss_clean]=minstr; //变换系统区域内容

if(objTimerout) window.clearTimeout(objTimerout);//停止获得聊天记录函数

OnlineNum();//启动在线人数统计

}

还原按钮:

function changemax() 

{

document.getElementById("eMsg")[xss_clean]=maxstr; //变换系统区域内容

document.getElementById("nc").value=nc; //获得呢称

getChat(); //获得聊天记录

}

十四、服务器连结文件 conn.asp

<%

dim conn

dim connstr

dim db

db="main.mdb" '数据库文件位置

connstr="Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & Server.MapPath(""&db&"")

set conn=server.createobject("ADODB.CONNECTION")

conn.open connstr

 

Function del1(s)  'IE时处理函数

del1=left(s,len(s)-1)

end function

 

Function  StreamToStr(sStream)   'Firefox下编码转换

dim  dr  

Set  dr=Server.CreateObject("Adodb.Stream")  

dr.Mode=3  

dr.Type=2  

dr.Open  

dr.Charset="GB2312"

dr.Position=0

dr.WriteText sStream

dr.Position=0  

dr.Charset="UTF-8"  

StreamToStr=dr.ReadText

StreamToStr= left(StreamToStr,len(StreamToStr)-1) 

dr.Close  

Set dr=Nothing  

End Function

%>

十五、Firefox兼容处理

     程序第一次测试时并不能在Firefox中正常运行,因为懒羊很少用Firefox,所以一直未在其环境下测试,后来与小编聊天时才发现这个问题,于是对程序作了调整,对于修改部分程序中已经用红色标注出来,下面就针对标注的知识点作一个简单的介绍。

1、    IE:document.getElementById("eMsg").style.top =document.documentElement.clientHeight - divHeight + parseInt(document.documentElement.scrollTop,10);

Firefox:document.getElementById("eMsg").style.top =(document.documentElement.clientHeight - divHeight + parseInt(document.documentElement.scrollTop,10))+"px";

IE中后面可以不加单位“px”而Firefox中却不可以,或许Firefox没IE智能吧,因此为了兼容干脆全部加上。

2、    CSS样式文件中在对.gn ul{margin:0;padding:0;list-style:none;}进行定义时,刚开始并没使用padding:0这条语句,然而在Firefox却转了行,原来Firefox只认识padding,因此我们在设置类似样式时,为了兼容起见可以将margin与padding全部设置为零。

3、    在信息发送采用快捷键时,原来的语句很简单,并没有如程序中作出判断:

if((event.keyCode==83)&&(event.altKey)){sendMessage();}

然而Firefox并不认可event.KeyCode,而必须采用event.which

var keycode = event.keyCode?event.keyCode:event.which?event.which:event.charCode;

keyCode用于返回的是功能键的编码
charCode用于返回数字和字符键的编码
which包含keyCode和charCode两种情况

4、    我们通过xmlDOM获得某一个节点具体值时,原来采用chatinfo[i].childNodes(0).text,然而在Firefox中对于.text并不支持,因此我们将代码改为

var nc=chatinfo[i].childNodes[0].firstChild.data;

还有一点值得注意,在表现数组时IE中可以用“( )”,而在Firefox中必须采用“[ ]”。

5、    编码要求

这一点算是最让懒羊头疼的了,原来程序全部采用GB2312,我们知道xmlhttp默认是以utf-8,但IE或许有一定的免役能力,能够识别,然而Firefox中却不可以,每次提交信息后添加到数据库时全部变成乱码,因此我们在后台不得不通过程序对传过来的参数进行编码转换,从UTF-8转为GB2312再存入数据库,具体的编码转换函数见conn.asp文件中的StreamToStr函数。然而有一点懒羊也不是很明白,为何在传递时非得加一个字符,因此就出现了前面的loadXML("get","quit.asp?frompage="+frompage+"a&b="+b+"&nc="+ nc+ "a",blankfunction);

这样的语句,当然在如果是在IE中服务器端同样也要通过del1对字符串进行处理去掉传递过来的那个字符。这里懒羊采用的方法比较笨,如果大家有好的方法不妨试一试。

 

     至此,所有的开发过程也就讲完了,你只需将客户端代码合成文件lanyangpl.js,然后目标网页通过以下语句调用即可使用:

<script src="interface.js"></script>

<script src="xml.js"></script>

<script src="lanyangpl.js"></script>

注意,请将代码段放置body内,特别是interface.js必须放进body内。

或许细心的朋友发现,此程序与新浪的woocall并不相同,woocall界面采用flash完成,当然有能力的朋友也可以通过flash去开发一个页面聊天系统,本教程中的所有代码可以正常运行,但离真正投入使用还有一段距离,希望大家在学习的过程在再加以完善,如果大家做出好的版本也请发给懒羊学习学习。

相关推荐

相关文章