不知上过ChinaRen校友录的朋友们有没有注意,ChinaRen在改版后很多方面都进行了较大的改动。例如留言与回复方面已经不再像以前那样,在每次提交后总得重新加载一下整个页面,碰到网速超慢时,只能干瞪着眼睛等待。那么现在这种炫丽的效果又是如何做到的呢,如果你觉得有兴趣,那就跟着我一起往下看吧! 了解Ajax的朋友也许知道其实这种炫丽效果的实现并不是一件很为难的事,当然如果你不了解何为Ajax那也没有关系,本节我们就通过打造一个新闻评论系统,来看看到底什么是Ajax,首先我们还是先了解一些基础东西。 什么是Ajax? Ajax提出者Jesse James Garrett在《Ajax:一个Web应用的新途径》中提到Ajax为“Asynchronous JavaScript + XML”的简称,也就是异步的JavaScript和XML处理。其包含: 用XHTML和CSS进行基于标准的表示方式: 采用DOM(document object model)动态显示和交互操作; 采用XML和XSLT进行数据交换和操作; 采用XMLHttpRequest进行异步数据获取; 采用JavaScript绑定上述技术应用; Ajax与传统Web应用有什么不同? Ajax与传统Web应用最大的不同就是Ajax可以对页面某一个区域进行局部加载,而不是像传统Web中每次页面请求后的都必须重新加载整个页面,特别在页面负载比较大的情况下,页面加载时间就比较长,用户多数时间就处在等待状态,而呈现给用户的仅仅是一片空白,而在Ajax的应用中就可以很好的避免这类事情的发生。 Ajax的工作原理是什么? Ajax主要是通过JavaScript对象中的XmlHttpRequest向服务器提出请求,并根据处理的结果更新页面。这样的更新不会使整个页面全部更新,而是根据用户的需要对某个区域进行局部更新,而且在更新的同时不影响其它区域的浏览。例如:搜狐个人博客中每个栏目后面的刷新按钮。 什么是XmlDom? XMLDOM是用来访问和操作XML文档的编程接口规范。XMLDOM被设计为可用于任何语言和任何操作系统。借助DOM,程序员可以创建XML文档、遍历其结构,增、改、删其元素。DOM将整个XML文档视作一棵树,文档级的元素是树的根。 下面我们就来看看几个与本教程相关的功能,值得注意的是以下方法或属性并不是同一个对象下,具体请看说明: getElementsByTagName 方法 说明:传回指定名称的元素集合。 语法:objNodeList = xmlDocument.getElementsByTagName(tagname); 例:var node=xmlDom.responseXML.getElementsByTagName("pl"); getAttribute()方法 说明:获得某个元素节点的属性值 语法:elementNode.getAttribute(name) 例:var tot=xmlDom.responseXML.getElementsByTagName("pl")[0].getAttribute("tot"); childNodes 属性 说明:传回一个节点列表,包含该节点所有可用的子节点。 语法:objNodeList=node.childNodes; 例:objNodeList = xmlDoc.childNodes; 如需具体的某一个节点, var u= xmlDoc.childNodes(0); Length属性 () 说明:返回一个节点列表中的节点数量 语法:nodelistObject.length 例:var len=node.length; 至此,基础知识已经讲完了,如果你还是不太了解的话,那建议你去看一些javascript相关的教程。下面我们就看这个新闻评论系统的具体实现原理 假设有一个页面index.asp,上半部分为评论列表显示区域,下面为评论提交区域。那么这样一个页面我们如何显示评论内容和提交评论呢? 传统:上半部分评论列表直接通过数据库查询语句读取并显示,每当提交新的评论时,先传递给处理页面,处理页面处理完毕后再返回index.asp这个页面,当然index.asp是重新加载获得新的评论。 Ajax::首先列表页面的内容是一个单独的xml文件(pl_list.asp),然后index..asp中的上半部分评论通过XmlHttpRequest请求pl_list.asp页面,并通过返回的结果传递到需要更新区域。提交评论同样如此,每次提交采用XmlHttpRequest请求提交处理程序,然后重新更新评论列表显示区域。 此新闻评论系统共分为五个部分,分别为数据库、前台页面、JS代码、服务器处理、CSS样式。 数据库的设计 PL表: 字段名 类型 长度 id 自动编号 user 文本 20 dateandtime 日期/时间 content 备注 newid 数字 前台页面:(index.htm) 如上图所示,前台页面共包括两部分,上半部分为页面评论列表显示,下半部分为提交评论。由于我们这里只是模拟一个新闻评论系统,并没有真正的新闻页面,那么在传递新闻ID的时候我们采用了一个默认值 〈input name="newsid" value="1" type="hidden"/〉。 代码:index.htm 〈%@LANGUAGE="VBSCRIPT" CODEPAGE="936"%〉 〈!DOCTYPE html PUBLIC "-//W3C//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〉 〈script src="main.js"〉〈/script〉 〈link href="main.css" rel="stylesheet" type="text/css" /〉 〈/head〉 〈body〉 〈div id="pllist"〉正在加载评论…… 〈script〉 loadDom();setTimeout("loadDom()",10000);〈/script〉 〈/div〉 〈div style="width:240px;font-size:12px;text-align:center"〉 〈fieldset〉〈legend〉评论〈/legend〉 呢称:〈input name="user" type="text" style="width:180px"/〉〈input name="newsid" value="1" type="hidden"/〉〈br/〉 内容:〈textarea name="content" style="width:180px;height:80px"〉〈/textarea〉〈br/〉 〈input name="submit" value="我要评论" onclick="fb();" type="button" /〉 〈/fieldset〉 〈/div〉 〈div style="font-size:12px;" id="msg"〉 〈/div〉 〈/body〉 〈/html〉 JS代码页(核心部分) main.js JS代码算是本系统的一个核心部分了,Ajax的体现基本全包含在这短短数十行的代码中,是连结前台与后台处理的一个桥梁,可谓是重中之重,为了更好的让大家理解整个功能,我们将分段介绍。 1、获得XmlHttp对象,创建并返回一个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(method,url,callback) method: http方法,例如:POST、GET、PUT及PROPFIND url: 请求的URL地址,可以为绝对地址也可以为相对地址 callback:自定义的返回处理函数 2.获得评论列表 此段代码的主要功能是根据服务器处理返回的信息更新前台页面的内容,主要包括显示评论列表、评论列表分页、跳转页数三个功能。 显示评论列表:getList函数 function getList(xmlDom) { var pllist=document.getElementById("pllist"); //获得页面pllist对象,此对象用来显示评论内容 var node=xmlDom.responseXML.getElementsByTagName("pllist");//获得pllist节点集合 var tot=xmlDom.responseXML.getElementsByTagName("pl")[0].getAttribute("tot");//获得pl节点tot属性值,这里指评论的总数量 var curpage=xmlDom.responseXML.getElementsByTagName("pl")[0].getAttribute("curpage");//获得pl节点curpage属性,这里指评论列表当前所在的页数,应用于翻页 if (tot!=0) //判断当前评论数是否为空 { var cont=""; var len=node.length;//获得pllist节点集合中节点的总数量 for(var i=0;i〈len;i++) { var u=node[i].childNodes(0).text;//获得节点第一个子节点的值,这里指呢称 var d=node[i].childNodes(1).text; //获得节点第二个子节点的值,这里指时间 var co=node[i].childNodes(2).text; //获得节点第三个子节点的值,这里指内容 var idnub=node[i].childNodes(3).text; //获得节点第四个子节点的值,这里指新闻ID cont+='〈div class="u"〉呢称:'+u+'〈/div〉〈div class="d"〉时间:'+d+'〈/div〉〈div class="idnub" onclick="del('+idnub+')" style="cursor:hand" onmouseout="this.style.background=\'\'" onmousemove="this.style.background=\'#99cc66\'"〉删除〈/div〉〈div class="co"〉内容:'+co+'〈/div〉'; //将所获得的评论内容生成一个字符串 } var cont1=pagecount(tot,curpage);//调用分页函数 cont+=cont1; pllist.innerHTML=cont;//将内容呈现 } else { pllist.innerHTML="暂无评论!"; } } 评论列表分页:pagecount函数 function pagecount(tot,cur) { var cont1=""; if (tot%5==0) //默认每页五条,这个要求与服务器端保持一致 { pages=parseInt(tot/5); } else { pages=parseInt(tot/5)+1; } for(var j=1;j〈=pages;j++) { if (j==cur) { cont1+="〈span〉"+j+"〈/span〉 "} else { cont1+="〈span style='cursor:hand;color:#0000ff' onmouseout='this.style.background=\"\"' onmousemove='this.style.background=\"#99cc66\"' onclick='gotopage("+j+")'〉"+j+"〈/span〉 "} } return cont1; } 跳转页数:gotopage函数 function gotopage(page) { loadXML("get","pl_list.asp?page="+page,getList); } function loadDom() //定时更新评论列表,初始化10秒钟 { loadXML("get","pl_list.asp",getList); setTimeout("loadDom()",10000) } 3.删除评论 function del(idnub) { var msg=document.getElementById("msg"); msg.innerText="正在删除……"; loadXML("get","pl_del.asp?id="+idnub,getdel); } function getdel(xmlDom) //删除后所触发的事件,更新页面 { var msg=document.getElementById("msg"); msg.innerText="删除成功!"; loadXML("get","pl_list.asp",getList); } 4.提交评论 function fb() //处理提交 { var msg=document.getElementById("msg"); var user=document.getElementById("user"); var content=document.getElementById("content") var newsid=document.getElementById("newsid") if (user.value=="") { alert("呢称不可为空!"); return false; } if (content.value=="") { alert("内容不可为空!"); return false; } msg.innerText="正在发表评论"; loadXML("get","pl_fb.asp?user="+user.value+"&content="+content.value+"&newsid="+newsid.value,getfb); } function getfb(xmlDom) //评论提交后所触发的事件,更新评论列表 { var msg=document.getElementById("msg"); msg.innerText=xmlDom.responseText; loadXML("get","pl_list.asp",getList); } 服务器处理程序 根据JS代码页的分段介绍,我们了解此系统的功能大致包括评论的显示处理、评论的删除处理、评论的提交处理三个功能,那么我们就根据这三个功能分别介绍。 评论的显示处理页面:pl_list.asp 此程序为asp生成xml文件,通过分页的方式将评论的内容以XML的形式呈现出来,我们可以单独运行。 代码: 〈!--#include file="conn.asp"--〉 〈% 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" Response.write("〈?xml version=""1.0"" encoding=""gb2312""?〉") currentpage=request("page") if currentpage="" or int(currentpage)=0 then currentpage=1 set rs=server.createobject("adodb.recordset") sql="select * from pl order by id desc" rs.cursorlocation=3 rs.open sql,conn,1,1 if not rs.bof or not rs.eof then rs.pagesize=5 rs.absolutepage=currentpage rowcount=rs.pagesize Response.write("〈pl tot='"&rs.recordcount&"' curpage='"¤tpage&"'〉") do while not rs.eof and rowcount〉0 Response.write("〈pllist〉") Response.write("〈user〉"&rs("user")&"〈/user〉") Response.write("〈dateandtime〉"&rs("dateandtime")&"〈/dateandtime〉") Response.write("〈content〉"&rs("content")&"〈/content〉") Response.write("〈id〉"&rs("id")&"〈/id〉") Response.write("〈/pllist〉") rowcount=rowcount-1 rs.movenext loop else Response.write("〈pl tot='"&rs.recordcount&"' curpage='"¤tpage&"'〉") end if rs.close set rs=nothing response.write("〈/pl〉") %〉 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 %〉 评论的删除处理页面:pl_list.asp 〈% Response.Charset="gb2312" %〉 〈% Session.CodePage=936 %〉 〈!--#include file="conn.asp"--〉 〈% id=request("id") if id="" then response.write("参数错误!") response.End() end if set rs=server.CreateObject("adodb.recordset") sql="select * from pl where id="&id rs.open sql,conn,1,3 rs.delete rs.update rs.close set rs=nothing response.write("删除成功!") %〉 评论的提交处理页面:pl_fb.asp 〈% Response.Charset="gb2312" %〉 〈% Session.CodePage=936 %〉 〈!--#include file="conn.asp"--〉 〈% user=request("user") content=request("content") newsid=request("newsid") set rs=server.CreateObject("adodb.recordset") sql="select * from pl" rs.open sql,conn,1,3 rs.addnew rs("user")=user rs("content")=content rs("newsid")=newsid rs("dateandtime")=time() rs.update rs.close set rs=nothing response.write("添加成功!") %〉 CSS样式 main.css 一个好的页面呈现效果离不开一个好的样式,当然我这个属于最基本的,算是看得清楚罢了,大家如果有兴趣可以对样式文件作修改。 .u { /*呢称*/ font-size: 12px; float:left; height:25px; line-height:20px; width:120px; } .d { /*时间*/ font-size: 12px; float:left; height:25px; line-height:20px; width:120px; } .idnub { /*删除*/ text-align:center; font-size: 12px; height:25px; line-height:25px; width:30px; } .co {/*内容*/ font-size: 12px; width:280px; } 这是我第一次尝试在asp中使用ajax,习惯于donet中的拖拖拉拉,突然用最原始的方式写代码还真有点不习惯,特别是缺少了那种所见即所得的效果,每一步的实现都得在不断的调试中完成,的确是一件很累的事情。当然随着Ajax式的程序开发愈来愈受欢迎,现在市面的框架、工具也越来越多,相信有那么一天,开发Ajax应用程序终究会变成一件易常简单的事。 |