ajax 编程技术 第九章 常见问题解决 模式

42
主主主主 主主 主主主主 主主 [email protected] [email protected] Ajax 编编编编 编编编 编编编编编编编编

Upload: edan

Post on 14-Jan-2016

133 views

Category:

Documents


5 download

DESCRIPTION

Ajax 编程技术 第九章 常见问题解决 模式. 9.1 设计模式背景知识. 设计模式是解决特定的常见问题的成熟技术或方法。我们会遇到成千上万的模式问题,不可能逐一介绍,本章只介绍采用 Ajax 技术来解决这些问题的常见方法。它们是: 表单验证设计模式; 鼠标悬停 (mouseover) 模式; 刷新模式; 错误处理模式。. 9.2 表单验证. 表单验证用于过滤无意义或恶意输入数据,保持系统安全。 问题 传统的验证用户输入的内容方法是,等待用户输入整页数据提交后,在服务器验证。响应很慢。如果只在客户端验证,就不能访问数据库中的细节数据。 - PowerPoint PPT Presentation

TRANSCRIPT

主讲教师:李艺主讲教师:李艺[email protected]@ustc.edu.cn

Ajax 编程技术第九章 常见问题解决模式

9-2 中国科大《 Ajax编程技术》

9.1 设计模式背景知识

设计模式是解决特定的常见问题的成熟技术或方法。我们会遇到成千上万的模式问题,不可能逐一介绍,本章只介绍采用 Ajax技术来解决这些问题的常见方法。它们是: 表单验证设计模式; 鼠标悬停 (mouseover)模式; 刷新模式; 错误处理模式。

9-3 中国科大《 Ajax编程技术》

9.2 表单验证

表单验证用于过滤无意义或恶意输入数据,保持系统安全。 问题

传统的验证用户输入的内容方法是,等待用户输入整页数据提交后,在服务器验证。响应很慢。如果只在客户端验证,就不能访问数据库中的细节数据。

解决的办法是同时在服务器和客户端进行验证。这就用到Ajax技术。

模式有两种模式可用于表单验证:

当值被改变,或字段焦点丢失时,提交此字段; 定期提交要验证的字段内容。

9-4 中国科大《 Ajax编程技术》

9.2 表单验证

示例:字段焦点丢失时提交数据1. 先在默认目录下创建名为mydata.mdb的 access数据库,库中有一个名为 users的表,字段有 2个:① ID字段:自动编号;② UserName字段:文本类型, 40个字符宽。假设表中已经输入用户姓名有: Peter, Alex, Kate

9-5 中国科大《 Ajax编程技术》

9.2 表单验证

2. 创建主文件 index.htm

<html xmlns="http://www.w3.org/1999/xhtml" ><head> <title>Form Validation Example</title> <link id="Link1" rel="stylesheet" href="FormValidation.css" type="text/css" /> <script type="text/javascript" src="FormValidation.js"></script> </head><body><form name="form1" id="form1" method="post" action="formcheck.php">User Name: <input id="UserName" type="text" onblur="Validate('UserName')" /><br/><span id="span"></span><br/><br />Address:<input id="Address" class="textbox" type="text" /><br /><br /><input type="button" value="Click here to submit details" /></form></body></html>

9-6 中国科大《 Ajax编程技术》

9.2 表单验证

3. FormValidation.js文件:var xHRObject = false;if (window.XMLHttpRequest) { xHRObject = new XMLHttpRequest(); }else if (window.ActiveXObject) { xHRObject = new ActiveXObject("Microsoft.XMLHTTP"); }function getData(){ if ((xHRObject.readyState == 4) && (xHRObject.status == 200)) { var serverText = xHRObject.responseText; if (serverText == "True") { span.innerHTML = "This user name has already been taken"; } if (serverText == "False") { span.innerHTML = "This user name is available"; } }}function getBody(newform, data){ var argument = data + "="; argument += encodeURIComponent(document.getElementById(data).value) return argument;}function Validate(data){ var newform = document.forms[0]; var bodyofform = getBody(newform, data); if (bodyofform != "UserName=") { xHRObject.open("POST", "Validate.php", true); xHRObject.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"); xHRObject.onreadystatechange = getData; xHRObject.send(bodyofform); ; } else { span.innerHTML = "Blank user names not allowed"; } }

9-7 中国科大《 Ajax编程技术》

9.2 表单验证

4. 创建 FormValidation.css文件:

.textbox{ position: absolute; left: 100px;}span#span{ color: Red;}

9-8 中国科大《 Ajax编程技术》

9.2 表单验证

创建 Validate.php文件:<?php $conn = new COM('ADODB.Connection') or exit('Cannot start ADO.');$rs = new COM('ADODB.Recordset') or die('Coult not make rs'); $connstring = "Provider=Microsoft.Jet.OLEDB.4.0; Data Source=".realpath('mydata.mdb').";"; $conn->Open($connstring); $sql = 'SELECT * from Users';$rs->Open($sql, $conn, 1, 3); $rs = $conn->Execute($sql);$check = "False"; while (!$rs->EOF) { while (!$rs->EOF) { if ($rs->Fields['UserName']->value == $_POST["UserName"]) { $check = "True"; } $rs->MoveNext(); } }$rs->Close(); $conn->Close(); $rs=null; $conn=null; echo $check;?>

9-9 中国科大《 Ajax编程技术》

9.2 表单验证

程序运行:用户姓名输入: Peter,服务器数据库中已经有此人姓名,不能再注册此姓名,所以输入无效:

9-10 中国科大《 Ajax编程技术》

9.2 表单验证

但如果输入库中没有的用户名 zhangsan, 则验证合格,输入通过。

9-11 中国科大《 Ajax编程技术》

9.3 鼠标悬停模式

鼠标悬停技术是Web页面上动态显示信息的常见方法,它不影响原始页面上信息的布局而动态显示某项的附加信息。

问题如何在不影响外观格局,不干扰用户当前活动的

情况下,显示关于某项的附加信息。这是鼠标悬停技术所擅长的本事。

模式可以利用弹出部分透明框架的形式显示关于特定

项的附加信息,而不会造成中断。部分透明是指页面上的原始信息不会变得不明显。

9-12 中国科大《 Ajax编程技术》

9.3 鼠标悬停模式

鼠标悬停示例一网页介绍 5个旅游目的地。当鼠标悬停在风景

地照片上,会得到前往该旅游风景地的详细信息。此示例使用了 boxover.js,严格来说,这里并不

需要 Ajax,然而此示例嫁接了使用 XML文件的 Ajax

代码,它通过旅游地组团代号 TarId,来确定鼠标悬停在哪张风景地图片上。并返回该风景地的详细 (旅游目的地,最佳旅游时间、报价等 )。

9-13 中国科大《 Ajax编程技术》

9.3 鼠标悬停模式

主页程序 index.htm:

<!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> <title>Mouse Over Example</title> <script type="text/javascript" src="boxover.js"></script> <script type="text/javascript" src="mouse.js"></script> </head><body><table align=center> <tr> <td colspan=4 align=center>旅游推介 </br> </tr> <tr> <td><a title="header=[<img src='01.jpg'/>] body=[01]'" href='c1.htm'><img src="01.jpg" border=0 /></a></td> <td><a title="header=[<img src='02.jpg'/>] body=[02]'" href='c2.htm'><img src="02.jpg" border=0 /></a></td> <td><a title="header=[<img src='03.jpg'/>] body=[03]'" href='c3.htm'><img src="03.jpg" border=0 /></a></td> <td><a title="header=[<img src='04.jpg'/>] body=[04]'" href='c4.htm'><img src="04.jpg" border=0 /></a></td> <td><a title="header=[<img src='05.jpg'/>] body=[05]'" href='c5.htm'><img src="05.jpg" border=0 /></a></td> </tr></table></body></html>

9-14 中国科大《 Ajax编程技术》

9.3 鼠标悬停模式

2. boxover.js:if (typeof document.attachEvent!='undefined') { window.attachEvent('onload',init); document.attachEvent('onmousemove',moveMouse); document.attachEvent('onclick',checkMove); }else { window.addEventListener('load',init,false); document.addEventListener('mousemove',moveMouse,false); document.addEventListener('click',checkMove,false);}var oDv=document.createElement("div");var dvHdr=document.createElement("div");var dvBdy=document.createElement("div");var windowlock,boxMove,fixposx,fixposy,lockX,lockY,fixx,fixy,ox,oy,boxLeft,boxRight,boxTop,boxBottom,evt,mouseX,mouseY,boxOpen,totalScrollTop,totalScrollLeft;boxOpen=false;ox=10;oy=10;lockX=0;lockY=0;function init() { oDv.appendChild(dvHdr); oDv.appendChild(dvBdy); oDv.style.position="absolute"; oDv.style.visibility='hidden'; document.body.appendChild(oDv);}

9-15 中国科大《 Ajax编程技术》

9.3 鼠标悬停模式function defHdrStyle() { dvHdr.innerHTML='<img style="vertical-align:middle" src="info.gif">&nbsp;&nbsp;'+dvHdr.innerHTML; dvHdr.style.fontWeight='bold'; dvHdr.style.width='150px'; dvHdr.style.fontFamily='arial'; dvHdr.style.border='1px solid #A5CFE9'; dvHdr.style.padding='3px'; dvHdr.style.fontSize='11px'; dvHdr.style.color='#4B7A98'; dvHdr.style.background='#D5EBF9'; dvHdr.style.filter='alpha(opacity=85)'; // IE dvHdr.style.opacity='0.85'; // FF}function defBdyStyle() { dvBdy.style.borderBottom='1px solid #A5CFE9'; dvBdy.style.borderLeft='1px solid #A5CFE9'; dvBdy.style.borderRight='1px solid #A5CFE9'; dvBdy.style.width='150px'; dvBdy.style.fontFamily='arial'; dvBdy.style.fontSize='11px'; dvBdy.style.padding='3px'; dvBdy.style.color='#1B4966'; dvBdy.style.background='#FFFFFF'; dvBdy.style.filter='alpha(opacity=85)'; // IE dvBdy.style.opacity='0.85'; // FF}

function checkElemBO(txt) {if (!txt || typeof(txt) != 'string') return false;if ((txt.indexOf('header')>-1)&&(txt.indexOf('body')>-1)&&(txt.indexOf('[')>-1)&&(txt.indexOf('[')>-1)) return true;else return false;}function scanBO(curNode) { if (checkElemBO(curNode.title)) { curNode.boHDR=getParam('header',curNode.title); curNode.boBDY=getParam('body',curNode.title); curNode.boCSSBDY=getParam('cssbody',curNode.title); curNode.boCSSHDR=getParam('cssheader',curNode.title); curNode.IEbugfix=(getParam('hideselects',curNode.title)=='on')?true:false; curNode.fixX=parseInt(getParam('fixedrelx',curNode.title)); curNode.fixY=parseInt(getParam('fixedrely',curNode.title)); curNode.absX=parseInt(getParam('fixedabsx',curNode.title)); curNode.absY=parseInt(getParam('fixedabsy',curNode.title)); curNode.offY=(getParam('offsety',curNode.title)!='')?parseInt(getParam('offsety',curNode.title)):10; curNode.offX=(getParam('offsetx',curNode.title)!='')?parseInt(getParam('offsetx',curNode.title)):10; curNode.fade=(getParam('fade',curNode.title)=='on')?true:false; curNode.fadespeed=(getParam('fadespeed',curNode.title)!='')?getParam('fadespeed',curNode.title):0.04; curNode.delay=(getParam('delay',curNode.title)!='')?parseInt(getParam('delay',curNode.title)):0; if (getParam('requireclick',curNode.title)=='on') { curNode.requireclick=true; document.all?curNode.attachEvent('onclick',showHideBox):curNode.addEventListener('click',showHideBox,false); document.all?curNode.attachEvent('onmouseover',hideBox):curNode.addEventListener('mouseover',hideBox,false); }

9-16 中国科大《 Ajax编程技术》

9.3 鼠标悬停模式else { // Note : if requireclick is on the stop clicks are ignored if (getParam('doubleclickstop',curNode.title)!='off') { document.all?curNode.attachEvent('ondblclick',pauseBox):curNode.addEventListener('dblclick',pauseBox,false); } if (getParam('singleclickstop',curNode.title)=='on') { document.all?curNode.attachEvent('onclick',pauseBox):curNode.addEventListener('click',pauseBox,false); } } curNode.windowLock=getParam('windowlock',curNode.title).toLowerCase()=='off'?false:true; curNode.title=''; curNode.hasbox=1; } else curNode.hasbox=2; }function getParam(param,list) { var reg = new RegExp('([^a-zA-Z]' + param + '|^' + param + ')\\s*=\\s*\\[\\s*(((\\[\\[)|(\\]\\])|([^\\]\\[]))*)\\s*\\]'); var res = reg.exec(list); var returnvar; if (param != "body") { if (res) return res[2].replace('[[','[').replace(']]',']'); else return ''; } else { if (res) { kink = mousebox(res[2].replace('[[','[').replace(']]',']')); return kink; } else return ''; }}

function getParam(param,list) { var reg = new RegExp('([^a-zA-Z]' + param + '|^' + param + ')\\s*=\\s*\\[\\s*(((\\[\\[)|(\\]\\])|([^\\]\\[]))*)\\s*\\]'); var res = reg.exec(list); var returnvar; if (param != "body") { if (res) return res[2].replace('[[','[').replace(']]',']'); else return ''; } else { if (res) { kink = mousebox(res[2].replace('[[','[').replace(']]',']')); return kink; } else return ''; }}function Left(elem){ var x=0; if (elem.calcLeft) return elem.calcLeft; var oElem=elem; while(elem){ if ((elem.currentStyle)&& (!isNaN(parseInt(elem.currentStyle.borderLeftWidth)))&&(x!=0)) x+=parseInt(elem.currentStyle.borderLeftWidth); x+=elem.offsetLeft; elem=elem.offsetParent; } oElem.calcLeft=x; return x;}

function Top(elem){ var x=0; if (elem.calcTop) return elem.calcTop; var oElem=elem; while(elem){ if ((elem.currentStyle)&& (!isNaN(parseInt(elem.currentStyle.borderTopWidth)))&&(x!=0)) x+=parseInt(elem.currentStyle.borderTopWidth); x+=elem.offsetTop; elem=elem.offsetParent; } oElem.calcTop=x; return x; }var ah,ab;function applyStyles() { if(ab) oDv.removeChild(dvBdy); if (ah) oDv.removeChild(dvHdr); dvHdr=document.createElement("div"); dvBdy=document.createElement("div"); CBE.boCSSBDY?dvBdy.className=CBE.boCSSBDY:defBdyStyle(); CBE.boCSSHDR?dvHdr.className=CBE.boCSSHDR:defHdrStyle(); dvHdr.innerHTML=CBE.boHDR; dvBdy.innerHTML=CBE.boBDY; ah=false; ab=false; if (CBE.boHDR!='') { oDv.appendChild(dvHdr); ah=true; } if (CBE.boBDY!=''){ oDv.appendChild(dvBdy); ab=true; } }

// Customised function for inner window dimensionfunction SHW() { if (document.body && (document.body.clientWidth !=0)) { width=document.body.clientWidth; height=document.body.clientHeight; } if (document.documentElement && (document.documentElement.clientWidth!=0) && (document.body.clientWidth + 20 >= document.documentElement.clientWidth)) { width=document.documentElement.clientWidth; height=document.documentElement.clientHeight; } return [width,height];}

var ID=null;function moveMouse(e) { //boxMove=true; e?evt=e:evt=event; CSE=evt.target?evt.target:evt.srcElement; if (!CSE.hasbox) { // Note we need to scan up DOM here, some elements like TR don't get triggered as srcElement iElem=CSE; while ((iElem.parentNode) && (!iElem.hasbox)) { scanBO(iElem); iElem=iElem.parentNode; } }

if ((CSE!=LSE)&&(!isChild(CSE,dvHdr))&&(!isChild(CSE,dvBdy))){ if (!CSE.boxItem) { iterElem=CSE; while ((iterElem.hasbox==2)&&(iterElem.parentNode)) iterElem=iterElem.parentNode; CSE.boxItem=iterElem; } iterElem=CSE.boxItem; if (CSE.boxItem&&(CSE.boxItem.hasbox==1)) { LBE=CBE; CBE=iterElem; if (CBE!=LBE) { applyStyles(); if (!CBE.requireclick) if (CBE.fade) { if (ID!=null) clearTimeout(ID); ID=setTimeout("fadeIn("+CBE.fadespeed+")",CBE.delay); } else { if (ID!=null) clearTimeout(ID); COL=1; ID=setTimeout("oDv.style.visibility='visible';ID=null;",CBE.delay); } if (CBE.IEbugfix) {hideSelects();} fixposx=!isNaN(CBE.fixX)?Left(CBE)+CBE.fixX:CBE.absX; fixposy=!isNaN(CBE.fixY)?Top(CBE)+CBE.fixY:CBE.absY; lockX=0; lockY=0; boxMove=true; ox=CBE.offX?CBE.offX:10; oy=CBE.offY?CBE.offY:10; } }

else if (!isChild(CSE,dvHdr) && !isChild(CSE,dvBdy) && (boxMove)) { // The conditional here fixes flickering between tables cells. if ((!isChild(CBE,CSE)) || (CSE.tagName!='TABLE')) { CBE=null; if (ID!=null) clearTimeout(ID); fadeOut(); showSelects(); } } LSE=CSE; } else if (((isChild(CSE,dvHdr) ||isChild(CSE,dvBdy))&&(boxMove))){ totalScrollLeft=0; totalScrollTop=0; iterElem=CSE; while(iterElem) { if(!isNaN(parseInt(iterElem.scrollTop))) totalScrollTop+=parseInt(iterElem.scrollTop); if(!isNaN(parseInt(iterElem.scrollLeft))) totalScrollLeft+=parseInt(iterElem.scrollLeft); iterElem=iterElem.parentNode; } if (CBE!=null) { boxLeft=Left(CBE)-totalScrollLeft; boxRight=parseInt(Left(CBE)+CBE.offsetWidth)-totalScrollLeft; boxTop=Top(CBE)-totalScrollTop; boxBottom=parseInt(Top(CBE)+CBE.offsetHeight)-totalScrollTop; doCheck(); } }

if (boxMove&&CBE) { // This added to alleviate bug in IE6 w.r.t DOCTYPE bodyScrollTop=document.documentElement&&document.documentElement.scrollTop?document.documentElement.scrollTop:document.body.scrollTop; bodyScrollLet=document.documentElement&&document.documentElement.scrollLeft?document.documentElement.scrollLeft:document.body.scrollLeft; mouseX=evt.pageX?evt.pageX-bodyScrollLet:evt.clientX-document.body.clientLeft; mouseY=evt.pageY?evt.pageY-bodyScrollTop:evt.clientY-document.body.clientTop; if ((CBE)&&(CBE.windowLock)) { mouseY < -oy?lockY=-mouseY-oy:lockY=0; mouseX < -ox?lockX=-mouseX-ox:lockX=0; mouseY > (SHW()[1]-oDv.offsetHeight-oy)?lockY=-mouseY+SHW()[1]-oDv.offsetHeight-oy:lockY=lockY; mouseX > (SHW()[0]-dvBdy.offsetWidth-ox)?lockX=-mouseX-ox+SHW()[0]-dvBdy.offsetWidth:lockX=lockX; } oDv.style.left=((fixposx)||(fixposx==0))?fixposx:bodyScrollLet+mouseX+ox+lockX+"px"; oDv.style.top=((fixposy)||(fixposy==0))?fixposy:bodyScrollTop+mouseY+oy+lockY+"px"; }}function doCheck() { if ( (mouseX < boxLeft) || (mouseX >boxRight) || (mouseY < boxTop) || (mouseY > boxBottom)) { if (!CBE.requireclick) fadeOut(); if (CBE.IEbugfix) {showSelects();} CBE=null; }}

function pauseBox(e) { e?evt=e:evt=event; boxMove=false; evt.cancelBubble=true;}function showHideBox(e) { oDv.style.visibility=(oDv.style.visibility!='visible')?'visible':'hidden';}function hideBox(e) { oDv.style.visibility='hidden';}var COL=0;var stopfade=false;function fadeIn(fs) { ID=null; COL=0; oDv.style.visibility='visible'; fadeIn2(fs);}function fadeIn2(fs) { COL=COL+fs; COL=(COL>1)?1:COL; oDv.style.filter='alpha(opacity='+parseInt(100*COL)+')'; oDv.style.opacity=COL; if (COL<1) setTimeout("fadeIn2("+fs+")",20); }function fadeOut() { oDv.style.visibility='hidden'; }

function isChild(s,d) { while(s) { if (s==d) return true; s=s.parentNode; } return false;}var cSrc;function checkMove(e) { e?evt=e:evt=event; cSrc=evt.target?evt.target:evt.srcElement; if ((!boxMove)&&(!isChild(cSrc,oDv))) { fadeOut(); if (CBE&&CBE.IEbugfix) {showSelects();} boxMove=true; CBE=null; }}function showSelects(){ var elements = document.getElementsByTagName("select"); for (i=0;i< elements.length;i++){ elements[i].style.visibility='visible'; }}function hideSelects(){ var elements = document.getElementsByTagName("select"); for (i=0;i< elements.length;i++){ elements[i].style.visibility='hidden'; }}

9-21 中国科大《 Ajax编程技术》

9.3 鼠标悬停模式

3. 创建mouse.js:

var tarid = null; var http = null;function mousebox(tarid){ if (window.ActiveXObject) { http = new ActiveXObject("Microsoft.XMLHTTP"); } else if (window.XMLHttpRequest) { http = new XMLHttpRequest(); } http.open("GET", "Catalogue.xml", false); http.send(null); var xml = http.responseXML; //Load XSL if (window.ActiveXObject) { var xsl = new ActiveXObject("MSXML2.FreeThreadedDomDocument.3.0"); xsl.async = false xsl.load("Catalogue.xsl") var template = new ActiveXObject("MSXML2.XSLTemplate") template.stylesheet = xsl processor = template.createProcessor() processor.input = xml processor.addParameter("TarId", tarid) processor.transform() //Transform return processor.output; }

else { var xsltProcessor = new XSLTProcessor(); //Load XSL http = new XMLHttpRequest(); http.open("GET", "Catalogue.xsl", false); http.send(null); xslStylesheet = http.responseXML; xsltProcessor.importStylesheet(xslStylesheet); xsltProcessor.setParameter(null, "TarId", tarid); //Transform var fragment = xsltProcessor.transformToFragment(xml, document); return new XMLSerializer().serializeToString(fragment); }}

9-22 中国科大《 Ajax编程技术》

9.3 鼠标悬停模式

创建 catalogue.xml:<?xml version="1.0" encoding="gb2312" ?><catalog> <trip> <Target> 甘肃敦皇 </Target> <goTime> 夏季 </goTime><TarId>02</TarId><Price> ¥ 4000</Price> </trip> <trip> <Target> 吉林长春 </Target><goTime> 冬季 </goTime><TarId>03</TarId><Price> ¥ 2000</Price> </trip> <trip> <Target>内蒙海拉尔 </Target><goTime> 夏季 </goTime><TarId>01</TarId><Price> ¥ 4000</Price> </trip> <trip> <Target> 四川九寨沟 </Target><goTime> 四季 </goTime><TarId>04</TarId><Price> ¥ 4500</Price> </trip> <trip> <Target> 陕西西安 </Target><goTime> 四季 </goTime><TarId>05</TarId><Price> ¥ 3000</Price> </trip></catalog>

9-23 中国科大《 Ajax编程技术》

9.3 鼠标悬停模式

5. 创建 catalogue.xsl:<?xml version="1.0" encoding="gb2312"?><xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="html" indent="yes" version="4.0" /> <xsl:param name="TarId" /> <xsl:template match="/"> <xsl:for-each select="//trip"> <xsl:if test="TarId=$TarId"> <span> <b>旅游线路 </b> : <xsl:value-of select="Target"/> </span><br/> <span> <b>最佳时间 </b> : <xsl:value-of select="goTime"/> </span><br/> <span> <b>组团代号 </b> : <xsl:value-of select="TarId"/> </span><br/> <span> <b>成行报价 </b> : <xsl:value-of select="Price"/> </span><br/> </xsl:if> </xsl:for-each> </xsl:template></xsl:stylesheet>

9-24 中国科大《 Ajax编程技术》

9.3 鼠标悬停模式

运行程序:

9-25 中国科大《 Ajax编程技术》

9.3 鼠标悬停模式

运行程序:鼠标悬停在第 4 幅图上,立即显示该风景地详细信息

9-26 中国科大《 Ajax编程技术》

9.4 轮询服务模式

有时候,我们希望页面能自动定时地轮询更新,而不是手动刷新。这就是我们本节要介绍的技术。

问题如何能定期地检查服务器上的信息?如果使用具有 GET方

法的 XMLHttpRequest 对象,则 IE会缓存调用的 XML页面,达不到轮询服务器定期自动更新的目的。这是我们面临的问题

解决模式这种异步行为叫轮询服务器。这种模式被称为页面流 (pag

e streaming)或服务流 (service streaming)。方法是,创建持续运行调用服务器上数据的脚本。一般程

序在第一次调用后都会退出程序,在此模式中,程序会循环调用函数,然后等待一定的时间,再调用这些函数。

9-27 中国科大《 Ajax编程技术》

9.4 轮询服务模式

例:创建一个包含股票价格的 XML文件,当我们在后台修改了 XML文件中的股票价格后,经过下一轮询问,变动的股票价格会自动显示在页面中:

1. 创建主文件 polling.htm:

<html xmlns="http://www.w3.org/1999/xhtml" ><head> <title>Polling The Server Example</title> <link id="Link1" rel="stylesheet" href="Polling.css" type="text/css" /> <script type="text/javascript" src="polling.js"></script> </head><body onload="getDocument()"> <span id="Stocks"></span></body></html>

9-28 中国科大《 Ajax编程技术》

9.4 轮询服务模式 创建 Polling.js 脚本文件:

var xHRObject = false;if (window.XMLHttpRequest) { xHRObject = new XMLHttpRequest(); }else if (window.ActiveXObject) { xHRObject = new ActiveXObject("Microsoft.XMLHTTP"); }function loadDocument(fileName) { var xmlDoc = null if (window.ActiveXObject) { xmlDoc = new ActiveXObject("MSXML2.DOMDocument.3.0") } else { document.implementation.createDocument("","",null); } xmlDoc.async = false; xmlDoc.load(fileName); return xmlDoc;}function transformToHTML(xmlDoc, xslDoc) { var html = ""; if (window.XSLTProcessor) { var xsltProc = new XSLTProcessor(); xsltProc.importStylesheet(xslDoc); var fragment = xsltProc.transformToFragment(xmlDoc, document); html = new XMLSerializer().serializeToString(fragment); } else if (window.ActiveXObject) { html = xmlDoc.transformNode(xslDoc); } return html;}

function getData(){ //Check to see if the XMlHttpRequest object is ready and whether it has //returned a legitmate response

if (xHRObject.readyState == 4 && xHRObject.status == 200) { var xml = loadDocument(“Stocks.xml”);// 装入 XML

var xsl = loadDocument(“Stocks.xsl”); // 装入 XSL

document.getElementById("Stocks").innerHTML = transformToHTML(xml, xsl); //Transform setTimeout("getDocument()", 5000); // 每隔 5 秒钟清除对象,调用 getDocument 函数 }} function getDocument(){ xHRObject.open("GET", "GetStocksList.php?id=" + Number(new Date()), true); xHRObject.onreadystatechange = getData; if (xHRObject.overrideMimeType) { xHRObject.overrideMimeType("text/plain"); } xHRObject.send(null);}

9-29 中国科大《 Ajax编程技术》

9.4 轮询服务模式

创建 GetStocksList.php文件:<?php $dom = new DomDocument('1.0');$dom->load('stocks.xml');$root = $dom->lastChild;srand(time());foreach ($root->childNodes As $child){ $RandomNumber = (rand()%100); if ($child->nodeType == 1) { foreach ($child->childNodes As $subchild) { if ($subchild->nodeName == "price") { $value = $subchild->textContent; $RandomPrice = (rand()%$value); $RandomPrice = $RandomPrice / 10; $direction = ""; if (($RandomNumber % 2) == 1) { $direction = "Down"; $value = $value - $RandomPrice; } else { $direction = "Up"; $value = $value + $RandomPrice; } $textNode = $dom->createTextNode($value); $subchild->nodeValue = ""; $newchild = $subchild->appendChild($textNode); }

if ($subchild->nodeName == "direction") { $textNode = $dom->createTextNode($direction); $subchild->nodeValue = ""; $newchild = $subchild->appendChild($textNode); } } }}$dom->save('stocks.xml');?>

9-30 中国科大《 Ajax编程技术》

9.4 轮询服务模式

准备后台股票数据的 XML文件 Stocks.xml:<?xml version="1.0" encoding="iso-8859-1" standalone="yes"?><stocks> <company> <name>Isotope International Ltd</name> <price>8.4</price> <direction>Down</direction> </company> <company> <name>Cartkeys Conglomerates</name> <price>3.2</price> <direction>Down</direction> </company> <company> <name>Merrible Networks Inc</name> <price>36.9</price> <direction>Down</direction> </company> <company> <name>Sable Strongholds</name> <price>38.4</price> <direction>Down</direction> </company></stocks>

9-31 中国科大《 Ajax编程技术》

9.4 轮询服务模式

创建 Stocks.xsl文件 :<?xml version="1.0" encoding="utf-8"?><xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"><xsl:output method="html" indent="yes" version="4.0"/> <xsl:template match="/"> <xsl:call-template name="DisplayStocks"></xsl:call-template> </xsl:template> <xsl:template name="DisplayStocks"> <table id="stocks"> <thead class="head"> <tr> <td>Company</td><td>Price</td><td>Direction</td> </tr> </thead> <tbody> <xsl:for-each select="//company"> <tr> <td class="border2"> <xsl:value-of select="name"/> </td> <td class="border2" align="center"> <xsl:value-of select="price"/> </td>

<xsl:choose> <xsl:when test="direction='Up'"> <td class="border2" style="color:blue;"> <xsl:value-of select="direction"/> </td> </xsl:when> <xsl:otherwise> <td class="border2" style="color:red;"> <xsl:value-of select="direction"/> </td> </xsl:otherwise> </xsl:choose> </tr> </xsl:for-each> </tbody> </table> </xsl:template></xsl:stylesheet>

9-32 中国科大《 Ajax编程技术》

9.4 轮询服务模式

运行:初始股价如下左图,在 Stocks.xml文件中将第一支股票价格修改成 8.9,然后保存,则页面自动更新后第一支股票的价格变成为 8.9 !见下右图:

9-33 中国科大《 Ajax编程技术》

9.5 错误处理模式

使用 Ajax的问题之一是某些技术可能会导致一些异常,也可能碰见页面延迟,或者出现根本不出现呈现的问题。这种问题可能是由小的输入错误或页面的拼写错误引起。

对于这些错误,我们指望应用程序更健壮些,而不是一出现故障就停止运行。本节只讨论应用程序可以处理的一些常见情况。如果出现错误,则可能是下面 3种错误之一: 404:无法找到页面 302:存在页面,但要求具有重定向权限; 200:无错误,但页面不显示。

9-34 中国科大《 Ajax编程技术》

9.5 错误处理模式

前述 3种错误中,首先介绍最后一种错误,因为前述 3种错误中的前 2个错误则比最后一种错误容易处理些。

对于第 3种错误,因为常见的解决方案对它起不了多大作用。这意味着服务器端代码或 XMLHttpReque

st 对象调用的代码存在错误。使得 responseText 或 r

esponseXML 属性为空。产生这种错误的常因是代码中的逻辑错误。它暗示了代码已经正确执行,但无返回结果。

在这种情况下, XMLHttpRequest 对象的 statu

s 属性将为 200。

9-35 中国科大《 Ajax编程技术》

9.5 错误处理模式

问题XMLHttpRequest 对象返回为 4的 readyState,但返回 2

00以外的 status时该怎么做? 解决模式

XMLHttpRequest 对象经历了初始化对象、发送数据和接收响应等一系列阶段。它从 0运行到 4。通常,我们希望 status属性返回 200, readyStatus返回 4。如果没有得到预期结果,则可能引起脚本崩溃。因为一旦返回值为 4的 readyStatus,除非重新设置,否则 readyStatus是不会发生改变的。我们有两种解决模式: 第一种模式是完全取消请求; 第二种模式是继续在指定的时间或请求次数内执行请求。下面来看看两种模式的实际示例。

9-36 中国科大《 Ajax编程技术》

9.5 错误处理模式

例 1:取消请求。以本章第 2节的示例为例。我们对用户键盘输入的用户名是否包含在服务器

上数据库中 UserName表中,并使用 XMLHttpReques

t 对象执行表单验证。注意, Internet上的各种干扰使得有可能不返回

status为 200的响应。在这种情况下,必须采取其他措施。通过将 XMLHttpRequest 对象调用的文件名改为不存在的文件名,来模拟 Internet上的干扰条件。

在 status不为 200的情况下,显示第三种替代信息。

9-37 中国科大《 Ajax编程技术》

9.5 错误处理模式

将 index.htm中的 FormValidation.js改为 FormValidation2.js

<html xmlns="http://www.w3.org/1999/xhtml" ><head> <title>Form Validation Example</title> <link id="Link1" rel="stylesheet" href="FormValidation.css" type="text/css" /> <script type="text/javascript" src="FormValidation2.js"></script> </head><body><form name="form1" id="form1" method="post" action="formcheck.php">User Name: <input id="UserName" type="text" onblur="Validate('UserName')" /><br/><span id="span"></span><br/><br />Address:<input id="Address" class="textbox" type="text" /><br /><br /><input type="button" value="Click here to submit details" /></form></body></html>

9-38 中国科大《 Ajax编程技术》

9.5 错误处理模式var xHRObject = false;if (window.ActiveXObject) { xHRObject = new ActiveXObject("Microsoft.XMLHTTP"); }else if (window.XMLHttpRequest){ xHRObject = new XMLHttpRequest(); }function getData(){ if ((xHRObject.readyState == 4)) { if (xHRObject.status == 200) { var serverText = xHRObject.responseText; if (serverText == "True") { span.innerHTML = "This user name has already been taken"; } if (serverText == "False") { span.innerHTML = "This user name is available"; } } else { span.innerHTML = " 现在不能确定库中是否存在输入的名称,提交后再检验 "; xHRObject.abort(); } }}function getBody(newform, data){ var argument = data + "="; argument += encodeURIComponent(document.getElementById(data).value) return argument;}

function Validate(data){ var newform = document.forms[0]; var bodyofform = getBody(newform, data); if (bodyofform != "UserName=") { xHRObject.open(“POST”, “thisfiledoesntexist.

php”, true); //不存在的文件,导致 status不等于 200的错误发生 xHRObject.setRequestHeader("Content-Type",

"application/x-www-form-urlencoded"); xHRObject.onreadystatechange = getData; xHRObject.send(bodyofform); ; } else { span.innerHTML = "Blank user names not allo

wed"; }}Function Change(){ if (state.innerHTML == "State:") { state.innerHTML = "County:" zipcode.innerHTML = "Postcode:" } else { state.innerHTML = "State:" zipcode.innerHTML = "Zipcode:" }}

// 以上是 FormValidation2.js程序

9-39 中国科大《 Ajax编程技术》

9.5 错误处理模式

运行程序,输入一个库中存在的姓名 Peter, 则出现 st

atus不为 200的错误:

9-40 中国科大《 Ajax编程技术》

9.5 错误处理模式

例 2:多次请求。以本章第 3节示例为例,修改 polling.htm文件:

<html xmlns="http://www.w3.org/1999/xhtml" ><head> <title>Polling The Server Example</title> <link id="Link1" rel="stylesheet" href="Polling.css" type="text/css" /> <script type="text/javascript" src="polling2.js"></script> </head><body onload="getDocument()"> <span id="Stocks"></span></body></html>

9-41 中国科大《 Ajax编程技术》

9.5 错误处理模式

将 polling.js文件修改成 polling2.js文件:var xHRObject = false;if (window.XMLHttpRequest) { xHRObject = new XMLHttpRequest(); }else if (window.ActiveXObject) { xHRObject = new ActiveXObject("Microsoft.XMLHTTP"); }function loadDocument(fileName) { var xmlDoc = null if (window.ActiveXObject) { xmlDoc = new ActiveXObject("MSXML2.DOMDocument.3.0") } else { document.implementation.createDocument("","",null); } xmlDoc.async = false; xmlDoc.load(fileName); return xmlDoc;}function transformToHTML(xmlDoc, xslDoc) { var html = ""; if (window.XSLTProcessor) { var xsltProc = new XSLTProcessor(); xsltProc.importStylesheet(xslDoc); var fragment = xsltProc.transformToFragment(xmlDoc, document); html = new XMLSerializer().serializeToString(fragment); } else if (window.ActiveXObject) { html = xmlDoc.transformNode(xslDoc); } return html;}

function getData(){ if (xHRObject.readyState == 4) { if (xHRObject.status == 200) { var xml = loadDocument("Stocks.xml"); // Load XML

var xsl = loadDocument("Stocks.xsl"); //Load XSL

document.getElementById("Stocks").innerHTML = transformToHTML(xml, xsl); //Transform setTimeout("getDocument()", 5000); } else { var Stocks = document.getElementById("Stocks"); if (Stocks.innerHTML.indexOf("available")==-1) { Stocks.innerHTML += “<br/><span> 当前股票信息不可用,仅显示最近的可用信息 </span>"; } xHRObject.abort(); setTimeout("getDocument()", 5000); } }} function getDocument(){ xHRObject.open("GET", "GetStocksList.php?id=" + Number(new Date()), true); xHRObject.onreadystatechange = getData; if (xHRObject.overrideMimeType) { xHRObject.overrideMimeType("text/plain"); } xHRObject.send(null);}

9-42 中国科大《 Ajax编程技术》

9.5 错误处理模式

运行程序 polling.htm,然后将 Apache或 IIS服务停止,在尝试 4 次后,出现下图所示的提示。当然,如果再次启动Web服务,则程序运行进入正常。