日志 >
技术交流
![]()
ajax技术
![]() 2007年5月18日 11:01 重新定义用户的工作流程: 左侧的应用程序时传统的Web体系结构的应用程序,并没有使用AJAX技术 中间的应用程序使用了部分的AJAX思想,页面中的一些元素(如超链接,表单等元素是通过异步方式从服务器端动态取得的) 最右边的应用程序完全使用AJAX实现 使用XMLHttpRequest对象 传统的Web程序的工作流程 使用XMLHttpRequest对象后的工作情况 使用XMLHttpRequest对象发送请求的三个步骤: o 创建XHR对象 o 准备请求数据,发送请求 o 当响应到达后,处理响应 创建XMLHttpRequest对象: var xhr; if (document.XMLHttpRequest) { xhr = new XMLHttpRequest(); } else { xhr = new ActiveXObject("Microsoft.XMLHTTP"); } else { alert("cannot use Ajax"); } 创建该对象写出这么多代码的原因,就是在不同的浏览器下对该对象的实现方式不同。所以为了要适应多种浏览器的要求,通过如上代码来创建XHR对象。 微软的JS中,并没有内置的XHR对象,而是通过ActiveX控件实现的,所以的IE浏览器下创建XHR对象必须通过ActiveX方式实现。而其它浏览器中的JS库中有内置的JS XHR对象,所以可以直接创建出来 发送请求: 在发送请求前,我们需要创建如下的信息: o 需要请求的URL地址(通过URL地址可以定位到服务器端的一个具体资源) o 请求的类型,POST方式还是GET方式 o 传递给服务器端的参数 o 注册响应到达后的JS回调函数的名字 调用时使用的三种函数参数格式: o open(http_method, url) o open(http_method, url, asynchronous) o open(http_method, url, asynchronous, userid, password) 说明: 第一个参数说明请求的方式,GET或者POST 第二个参数请求的服务器端资源的URL地址 第三个参数,采用异步方式还是同步方式发送请求(说明异步请求和同步请求的区别) 第四个参数,如果服务器端采用了HTTP身份认证方式,那么需要给出认证的用户名和密码 例如: xhr.open('GET', 'servlets/ajax/getItem?id=321', true); 设置回调函数的名字: xhr.onreadystatechange = parseResponse; 如果采用POST方式,那么提交给服务器的数据需要调用send方法来发送数据;如果是GET方式那么send方法给空字符串参数即可 xhr.send('id=321'); 处理响应: 将请求发送给服务器端后,服务器端的对应程序就会被执行;并将执行后结果返回给客户端,通过注册的处理响应的JS函数来处理响应数据。 在你处理响应的JS函数中,需要判断响应的状态。通过readyState来判断: 值 状态 描述 0 Uninitialized open()函数没有被调用 1 Loading open()函数正在被调用 2 Loaded send()函数被调用 3 Interactive 服务器端正在返回结果 4 Complete 请求结束,并且服务器端已经结束发送数据到客户端 在处理响应的方法中: xhr.onreadystatechange = function(){ var ready = xhr.readyState; if (ready == 4){ parseCompletedResponse(xhr); } }; 在status中含有响应的状态码,通过响应的状态码可以获得响应的状态。如200表示响应正常、404表示资源未找到、500表示服务器端程序有错误 xhr.onreadystatechange = function(){ var ready = xhr.readyState; if (ready == 4) { var status = xhr.status; if (status >= 200 && status < 300) { parseCompletedResponse(xhr); } else { parseErroredResponse(xhr); } } }; 响应提供了两个对象:responseText和responseXML。分别用来获取不同文本格式的响应和XML格式的响应。 其它的一些响应中的方法: abort():放弃请求。即使请求已经被发送,服务器端已经产生响应,也会忽略响应的结果,而且结束处理。 setRequestHeader(header,value):设置请求的头部信息。例如: xhr.setRequestHeader( 'Content-type', 'application/x-www-form-urlencoded' ); 客户端发送XML格式数据到服务器端的时候,需要对文档的编码进行设置。 xhr.setRequestHeader( 'Content-type', 'application/xml; charset=UTF-8' ); xhr.send("<data source='ajax in practice'>hello world</data>"); getResponseHeader(header)和getAllResponseHeaders()方法:用来获取响应的头部信息。getAllResponseHeaders将取回所有响应的头部的名字。getResponseHeader方法将根据头部的key值取出value值。 if (xhr.getResponseHeader("Server") .indexOf("Microsoft-IIS") != -1 ) { alert("The server is a Microsoft IIS server."); } 使用Prototype的Ajax.Request对象来发送请求 使用原始的方式发送请求底层会需要做很多的工作。那么可以通过使用Prototype包中对原始类型的封装来完成请求的操作。 练习:hello1.html和hello1.jsp 使用${'wigetId'}来访问指定的HTML节点 练习:hello2.html和hello2.jsp 在服务器端生成JavaScript代码到客户端。在客户端通过使用eval()来调用生成后的JS代码 练习:hello3.html和hello3.jsp 在练习3中的两个问题:1.服务器端的代码和客户端的代码耦合在一起,因为需要在服务器端直到客户端节点的ID才能通过JS将数据插入到这个节点。如果对客户端的页面进行修改的时候页需要对服务器端的代码做修改以保持他们之间的一致性;2.通过使用innerHTML来插入数据方式。 每次在标题中显示当前用户的名字,而在左侧的两个表格中显示历史的信息。 通过在服务器端生成一个JS代码,该JS代码不想练习3中的那样,而是很简单的调用一个JS函数并将服务器端生成的数据传递给该函数,来改变显示的内容 练习:hello4.html和hello4.jsp 分清客户端和服务器端程序的职责,客户端程序用来完成流程控制,而服务器端程序用来完成业务处理。 通过使用JSON(JavaScript Object Notation)和XML来传递数据。 什么时JSON:轻量级的数据交换格式。很容易被服务器端和客户端的JavaScript程序解析。 在JSON中,有一半的是通过JS规范提供的。也就是在JS中可以直接使用。还有一半可以通过使用第三方的类库来完成。 JSON的格式。例如创建一个变量customers,在其中的一个detail的属性中存有一个数组来保存用户的信息。用户含有num,name和city属性。 var customers = { "details": [ {"num": "1","name":"JBoss","city":"Atlanta"}, {"num": "2","name":"Red Hat","city":"Raleigh"}, {"num": "3","name":"Sun","city":"Santa Clara"}, {"num": "4","name":"Microsoft","city":"Redmond"} } ; 以上就是通过JSON规则来定义了变量。以上我们写的代码就是标准的JS中的代码。 以上的变量中的数据通过JS也和容易的可以访问到,例如: alert (customers.details[2].name); 如果以上的变量的使用是通过string来完成的,那么代码如下: var customerTxt = "{ 'details': [ " + "{'num': '1','name':'JBoss','city':'Atlanta'}, " + " {'num': '2','name':'Red Hat','city':'Raleigh'}, " + " {'num': '3','name':'Sun','city':'Santa Clara'}, " + " {'num': '4','name':'Microsoft','city':'Redmond'}" + "] }" ; var cust = eval ('(' + customerTxt + ')'); alert (cust.details[0].city); //shows 'Atlanta' 因为string会经常使用,因为服务器端传递给客户端的数据就是string类型的数据,所以对这样的数据进行处理的使用需要使用eval函数然后才能进行访问和处理。 如果在页面直接使用JSON的话,采用方式一;如果是对服务器端产生的响应数据进行处理的话,那么采用方式二。 使用JSON的原理示意图: 标准的JS中并没有提供方法将对象转换为JSON格式的数据。也没有将Java中的数据转换为JSON格式数据的方法,所以这就需要采用第三方的类库来帮助我们更快更好的完成这个要求。 在http://www.json.org 练习:hello5.html和hello5.jsp使用JSON来传递数据。 虽然在网络上通过使用JSON来传递数据很方便,但是不管作为客户端还是服务器都需要将对应的JSON字符串转换为对象。如何才能快速的转换这些对象呢?采用第三方的工具包。在客户端使用JSON.js在服务器端使用json-lib.jar 练习:hello5a.html和hello5a.jsp 使用XML方式传递数据。在多数情况下服务器可以将数据以XML格式返回给客户端,而并非一定使用HTML格式。尤其是在SOA体系框架等情况下,使用这种方式就更加频繁。下面通过一个练习说明服务器端讲一个XML格式的数据发送给客户端,客户端解析这个XML文件,并将内容更新到HTML中。 练习:hello6.html和hello6.jsp AJAX方式调用Web Service dojo工具: 开源的JS代码库,用来发送异步的请求。对XHT进行了JS级别的封装,方便客户端调用。 下载地址:http://dojotoolkit.org/download/ 将下载后的dojo包中的dojo.js文件导入项目,就可以利用这个包中的JS代码来发送异步请求。 function lookup() { dojo.io.bind( { url: 'phone.jsp?who='+document.lookupForm.who.value, mimetype: 'text/plain', load: function(type, data, req) { document.getElementById('displayArea').innerHTML = data; } } ); } 通过bind方法来发送异步的请求,mime类型设置响应的类型是什么。load用来定义回调方法。当响应到达后会调用这个方法。 练习:phone.html和phone.jsp 上面的例子中发送请求时候还需要将提交的数据通过JS获取到,然后再加入到请求的字符串中,这种方式给我们编写JS代码带来了稍许的麻烦,所以dojo提供了另外的方式,通过指定要提交的表单名字来提交整个表单中的数据。 <script type="text/javascript"> function lookup() { dojo.io.bind( { url: 'phone.jsp', mimetype: 'text/plain', load: function(type, data, req) { document.getElementById('displayArea').innerHTML=data; }, formNode: document.lookupForm } ); } </script> 练习:phone2.jsp prototypes:另外一个开源的JS库,同样用来方便发送异步的请求。 下载地址:http://prototype.conio.net function updateSizes() { if ($F('color')=='') return; new Ajax.Request('getSizes.jsp?color=' + $F('color'), { method: 'get', onSuccess: populateSizes, onFailure: function(r) { throw new Error( 'Updates sizes failed: ' + r.statusText ); } } ); } 使用$F('color')直接获得表单中的输入域的值。 JSP中返回的是JSON字符串,通过eval方法来处理字符串 通过onFailure方法来处理异常问题。 通过onSuccess方法来设定响应函数,处理响应。 prototypes使用基础: ${}用来引用页面中的对象,等同于document.getElementById("") ${}还可以用来引用元素作为数组,例如: var myElements = $('foo', 'bar', 'fooBar'); for (var i = 0; i < myElements.length; i++) { myElements[i].value = "new value"; } 取得表单中的值: var myValue = document.getElementById('foo').value; var myValue = $F('foo'); 上面的方式进行处理的时候,还需要通过使用JS代码来处理结果。在prototypes中提供了另外一种自动更新的方式。 function update() { new Ajax.Updater('timeDisplay','date.jsp', { method: 'get' } ); } 该方法知名需要更新的域的名字,和请求方式。 例:date.html和date.jsp 上例中的时间更新只有当用户点击了按钮会才能更新,如果指定时间让其自动更新(也就是客户端在给定时间间隔内自动发送请求)在Prototypes中提供了另外一种方式来完成这样的需求。 <script> function update() { new Ajax.PeriodicalUpdater( 'timeDisplay', 'date2.jsp', { method: 'get', frequency: 5 } ); } </script> jQuery: DWR:使用该包可以通过JS轻松的调用服务器端Servlet。 配置DWR: 在web.xml中添加如下的内容: <servlet> <servlet-name>DwrServlet</servlet-name> <servlet-class>uk.ltd.getahead.dwr.DWRServlet</servlet-class> <init-param> <param-name>debug</param-name> <param-value>true</param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>DwrServlet</servlet-name> <url-pattern>/dwrserver/*</url-pattern> </servlet-mapping> JS中处理事件的方式: <html> <head> <title>Events!</title> <script type="text/javascript"> window.onload = function() { document.getElementById('anImage').onclick = function() { alert('Woof!'); } }; </script> </head> <body> <img src="image.jpg" id="anImage"/> </body> </html> 思考:如果将上面的代码改写成如下的样子,运行时会是什么结果? <html> <head> <title>Events!</title> <script type="text/javascript"> window.onload = function() { document.getElementById('anImage').onclick = function() { alert('Woof!'); } document.getElementById('anImage').onclick = function() { alert('Woof again!'); } }; </script> </head> <body> <img src="image.jpg" id="anImage"/> </body> </html> 另外更加细致的处理事件的方式: <html> <head> <title>Events!</title> <script type="text/javascript"> window.onload = function() { document.getElementById('anImage').addEventListener( 'click', function() { alert('Woof!'); }, false); document.getElementById('anImage').addEventListener( 'click', function() { alert('Woof again!'); }, false); }; </script> </head> <body> <img src="image.jpg" id="anImage"/> </body> </html> 再做修改: <html> <head> <title>Events!</title> <script type="text/javascript"> window.onload = function() { if (document.getElementById('anImage').attachEvent) { document.getElementById('anImage').attachEvent( 'onclick', function() { alert('Woof!'); }); document.getElementById('anImage').attachEvent( 'onclick', function() { alert('Woof again!'); }); } else { document.getElementById('anImage').addEventListener( 'click', function() { alert('Woof!'); }, false); document.getElementById('anImage').addEventListener( 'click', function() { alert('Woof again!'); }, false); } } </script> </head> <body> <img src="image.jpg" id="anImage"/> </body> </html> 在修改成可以自由处理事件方式: <html> <head> <title>Events!</title> <script type="text/javascript"> window.onload = function() { document.getElementById('anImage').onclick = function(event) { if (!event) event =window.event; var target = event.target ? event.target : event.srcElement; document.getElementById('info').innerHTML += 'I woof at ' + target.id + '!<br/>'; } } </script> </head> <body> <img src="image.jpg" id="anImage"/> <div id="info"></div> </body> </html> ![]() |
评论列表
/x02").replace(//[//quote/]/g,"/x01"); for(var i=0;i<2;i++) s=s.replace(//x03([^/x03/x01/x02]*?)/x02([^/x03/x01/x02]*?)/x01/g, function(a,b,c){ return '
'+b+'引用内容:'; }); return s.replace(/[/x03/x02/x01]/g,""); } var bLoaded = false; function checkMsgReply(obj) { if(!bLoaded) top.includeJS('/qzone/blog/script/common.js', function(){bLoaded=true;checkMsgReply(obj)}, document); else checkReply(obj); if(obj.checked){ MAX_COMMENT_LEN = 500; } else { MAX_COMMENT_LEN = 4500; } _fontCount = MAX_COMMENT_LEN; //字数限制 if(!window.sendCommentEditor) return; if(sendCommentEditor.editorArea.editMode == 1) toCountFont(sendCommentEditor.id, "html"); else toCountFont(sendCommentEditor.id, "text"); } function showMsgLeftCnt() { if(!bLoaded) top.includeJS('/qzone/blog/script/common.js', function(){bLoaded=true;showMsgLeftCnt();}, document); else showLeftSMS(); } function selectBlogPaper() { if(checkLogin() <= 10000) { top.showLoginBox("mall"); return; } if(!!top.g_JData["blogContent"]) { if(parent.g_iLoginUin == parent.g_iUin) { location.href="/qzone/newblog/blogeditor.html?paperid=" + parent.g_JData["blogContent"].data.lp_id + "&paperstyle=" + parent.g_JData["blogContent"].data.lp_style + "&paperdialog=1"; } else { parent.location.href="http://user.qzone.qq.com/" + parent.g_iLoginUin + "/addNewBlog?paperid=" + parent.g_JData["blogContent"].data.lp_id + "&paperstyle=" + parent.g_JData["blogContent"].data.lp_style; } } else { top.showMsgBox("抱歉,暂时无法获取该信纸信息!", 1, 2000); } } /** * 批量删除中选择全选 */ function selectAllComments(bChecked) { var oList = document.getElementsByName("commentCheckBox"); if(oList.length==0) return; for(var i=0; i 0){ dalert(null, parent.g_XDoc["delBatchReply"].xml, 2000); delete parent.g_XDoc["delBatchReply"]; return; } dalert(null, parent.g_XDoc["delBatchReply"].xml, 2000, 2); contentProperty.totalCommentNumber -= nDeleteCnt; //清理cache with(contentProperty){ delete parent.g_XDoc["blogRoot"].contentHSList[currentBlogid]; pageList = {}; pageIndexMap = []; currentCommentPage = lastCommentPage = (!contentProperty.nowaPage)?0:nowaPage[3]; parent.g_XDoc["blogRoot"].replyNumUpdateHSmap[currentBlogid] = totalCommentNumber; parent.isRefreshTop = true; if(currentCommentPage == 0) { setTimeout(contentInit, 1000); } else{ var tp = Math.ceil(totalCommentNumber/PAGE_COMMENT_NUM); var num = totalCommentNumber%PAGE_COMMENT_NUM; if(num==0 || currentCommentPage10000 && top.g_iLoginUin!=top.g_iUin) { $("msgboardSelfReply").style.display = ""; $("blogSelPaper").title = "我也要使用此信纸写日志"; } setTimeout(contentInit,50); //]]> </script>'+c+'
共0篇评论,第1页/共0页
批量删除 取消批量删除
共0篇评论,第1页/共0页