1 / 42

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

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

edan
Download Presentation

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

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


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

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

  3. 9.2 表单验证 表单验证用于过滤无意义或恶意输入数据,保持系统安全。 • 问题 传统的验证用户输入的内容方法是,等待用户输入整页数据提交后,在服务器验证。响应很慢。如果只在客户端验证,就不能访问数据库中的细节数据。 解决的办法是同时在服务器和客户端进行验证。这就用到Ajax技术。 • 模式 有两种模式可用于表单验证: • 当值被改变,或字段焦点丢失时,提交此字段; • 定期提交要验证的字段内容。 9-3

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

  5. 9.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-5

  6. 9.2 表单验证 • 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-6

  7. 9.2 表单验证 • 创建FormValidation.css文件: .textbox { position: absolute; left: 100px; } span#span { color: Red; } 9-7

  8. 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-8

  9. 9.2 表单验证 • 程序运行:用户姓名输入:Peter,服务器数据库中已经有此人姓名,不能再注册此姓名,所以输入无效: 9-9

  10. 9.2 表单验证 • 但如果输入库中没有的用户名zhangsan, 则验证合格,输入通过。 9-10

  11. 9.3 鼠标悬停模式 鼠标悬停技术是Web页面上动态显示信息的常见方法,它不影响原始页面上信息的布局而动态显示某项的附加信息。 • 问题 如何在不影响外观格局,不干扰用户当前活动的情况下,显示关于某项的附加信息。这是鼠标悬停技术所擅长的本事。 • 模式 可以利用弹出部分透明框架的形式显示关于特定项的附加信息,而不会造成中断。部分透明是指页面上的原始信息不会变得不明显。 9-11

  12. 9.3 鼠标悬停模式 • 鼠标悬停示例 一网页介绍5个旅游目的地。当鼠标悬停在风景地照片上,会得到前往该旅游风景地的详细信息。 此示例使用了boxover.js,严格来说,这里并不需要Ajax,然而此示例嫁接了使用XML文件的Ajax代码,它通过旅游地组团代号TarId,来确定鼠标悬停在哪张风景地图片上。并返回该风景地的详细(旅游目的地,最佳旅游时间、报价等)。 9-12

  13. 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-13

  14. 9.3 鼠标悬停模式 • 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-14

  15. 9.3 鼠标悬停模式 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); } 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 } 9-15

  16. 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 ''; } } 9-16

  17. 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; } }

  18. // Customised function for inner window dimension function 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; } }

  19. 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; } }

  20. 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'; } }

  21. 9.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-21

  22. 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-22

  23. 9.3 鼠标悬停模式 • 创建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-23

  24. 9.3 鼠标悬停模式 • 运行程序: 9-24

  25. 9.3 鼠标悬停模式 • 运行程序:鼠标悬停在第4幅图上,立即显示该风景地详细信息 9-25

  26. 9.4 轮询服务模式 有时候,我们希望页面能自动定时地轮询更新,而不是手动刷新。这就是我们本节要介绍的技术。 • 问题 如何能定期地检查服务器上的信息?如果使用具有GET方法的XMLHttpRequest对象,则IE会缓存调用的XML页面,达不到轮询服务器定期自动更新的目的。这是我们面临的问题 • 解决模式 这种异步行为叫轮询服务器。这种模式被称为页面流(page streaming)或服务流(service streaming)。 方法是,创建持续运行调用服务器上数据的脚本。一般程序在第一次调用后都会退出程序,在此模式中,程序会循环调用函数,然后等待一定的时间,再调用这些函数。 9-26

  27. 9.4 轮询服务模式 • 例:创建一个包含股票价格的XML文件,当我们在后台修改了XML文件中的股票价格后,经过下一轮询问,变动的股票价格会自动显示在页面中: • 创建主文件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-27

  28. 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-28

  29. 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-29

  30. 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-30

  31. 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-31

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

  33. 9.5 错误处理模式 使用Ajax的问题之一是某些技术可能会导致一些异常,也可能碰见页面延迟,或者出现根本不出现呈现的问题。这种问题可能是由小的输入错误或页面的拼写错误引起。 对于这些错误,我们指望应用程序更健壮些,而不是一出现故障就停止运行。本节只讨论应用程序可以处理的一些常见情况。如果出现错误,则可能是下面3种错误之一: • 404:无法找到页面 • 302:存在页面,但要求具有重定向权限; • 200:无错误,但页面不显示。 9-33

  34. 9.5 错误处理模式 前述3种错误中,首先介绍最后一种错误,因为前述3种错误中的前2个错误则比最后一种错误容易处理些。 对于第3种错误,因为常见的解决方案对它起不了多大作用。这意味着服务器端代码或XMLHttpRequest对象调用的代码存在错误。使得responseText 或 responseXML 属性为空。产生这种错误的常因是代码中的逻辑错误。它暗示了代码已经正确执行,但无返回结果。 在这种情况下,XMLHttpRequest 对象的status属性将为200。 9-34

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

  36. 9.5 错误处理模式 • 例1:取消请求。以本章第2节的示例为例。 我们对用户键盘输入的用户名是否包含在服务器上数据库中UserName表中,并使用XMLHttpRequest对象执行表单验证。 注意,Internet上的各种干扰使得有可能不返回status为200的响应。在这种情况下,必须采取其他措施。通过将XMLHttpRequest对象调用的文件名改为不存在的文件名,来模拟Internet上的干扰条件。 在status不为200的情况下,显示第三种替代信息。 9-36

  37. 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-37

  38. 9.5 错误处理模式 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 allowed"; } } Function Change() { if (state.innerHTML == "State:") { state.innerHTML = "County:" zipcode.innerHTML = "Postcode:" } else { state.innerHTML = "State:" zipcode.innerHTML = "Zipcode:" } } // 以上是FormValidation2.js程序 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; } 9-38

  39. 9.5 错误处理模式 • 运行程序,输入一个库中存在的姓名Peter, 则出现status不为200的错误: 9-39

  40. 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-40

  41. 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-41

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

More Related