[轉(zhuǎn)帖]10 分鐘|全面圖解 AJAX
當(dāng)前位置:點(diǎn)晴教程→知識(shí)管理交流
→『 技術(shù)文檔交流 』
:10 分鐘|全面圖解 AJAX
閱讀本文需要 30 分鐘,請(qǐng)先收藏轉(zhuǎn)發(fā)后再看。 先上原理圖:(另外這張圖是我在博客園畫(huà)的圖,所以水印是博客園的,也歡迎大家關(guān)注我的博客園。) 背景:1. 傳統(tǒng)的 Web 網(wǎng)站,提交表單,需要重新加載整個(gè)頁(yè)面。 2. 如果服務(wù)器長(zhǎng)時(shí)間未能返回 Response,則客戶(hù)端將會(huì)無(wú)響應(yīng),用戶(hù)體驗(yàn)很差。 3. 服務(wù)端返回 Response 后,瀏覽器需要加載整個(gè)頁(yè)面,對(duì)瀏覽器的負(fù)擔(dān)也是很大的。 4. 瀏覽器提交表單后,發(fā)送的數(shù)據(jù)量大,造成網(wǎng)絡(luò)的性能問(wèn)題。 問(wèn)題:1. 如何改進(jìn)? 2.AJAX 是什么? 3. 有什么優(yōu)勢(shì)? 4. 有什么缺點(diǎn)? 一、什么是 AJAX1. 為什么需要 AJAX當(dāng)需要從服務(wù)器獲取數(shù)據(jù),并刷新頁(yè)面的操作,如果不采用 AJAX,則需要用提交整個(gè)表單的方式,當(dāng)提交表單時(shí),發(fā)送請(qǐng)求給服務(wù)器,頁(yè)面需要等待服務(wù)器發(fā)送完 response 后,頁(yè)面才能恢復(fù)操作。 2.AJAX 的概念:1.AJAX = 異步 Javascript 和 XML。 2.AJAX 是一種用于創(chuàng)建快速動(dòng)態(tài)網(wǎng)頁(yè)的技術(shù)。 3. 通過(guò)在后臺(tái)與服務(wù)器進(jìn)行少量數(shù)據(jù)交換,可以使網(wǎng)頁(yè)實(shí)現(xiàn)異步更新。 4. 可以在不重新加載整個(gè)網(wǎng)頁(yè)的情況下,對(duì)網(wǎng)頁(yè)的某部分進(jìn)行更新。 3. 什么叫異步當(dāng)前頁(yè)面發(fā)送一個(gè)請(qǐng)求給服務(wù)器,當(dāng)前頁(yè)面不需要等待服務(wù)器響應(yīng)才能操作網(wǎng)頁(yè)。發(fā)送完請(qǐng)求之后,當(dāng)前頁(yè)面可以繼續(xù)瀏覽,操作。 4. 什么叫局部刷新我們可以用兩種方式來(lái)實(shí)現(xiàn)部分刷新。 1. iframe 頁(yè)面重載的方式。 這種方式雖然實(shí)現(xiàn)了部分刷新,但是是頁(yè)面的重載,所以也會(huì)帶來(lái)性能上的問(wèn)題。 Step1. 在頁(yè)面中定義一個(gè) Iframe <iframe id="indexFrame" name="index" width="1000" height="800" frameborder="0" marginwidth="0" marginheight="0" scrolling="yes" style="margin-top:100px;"></iframe> Step2. 設(shè)置 Iframe 的 src var indexFrame = document.getElementById("indexFrame");indexFrame.src = "introduction.php"; Step3. 添加一個(gè) button 的點(diǎn)擊事件,當(dāng)點(diǎn)擊這個(gè) button 時(shí),重新設(shè)置 Iframe 的 src,實(shí)現(xiàn) iframe 里面的頁(yè)面刷新。Iframe 外面的內(nèi)容不刷新。 <button id="room" onclick='IndexClick("room")'>Click Me!</button> function IndexClick(moduleKey) { var indexFrame = document.getElementById("indexFrame"); if(indexFrame == null) { indexFrame = parent.document.getElementById("indexFrame"); } var url = "introduction.php"; switch (moduleKey) { case "introduction": url = "introduction.php"; break; case "room": url = "room.php"; break; default: { } } indexFrame.src = url;} 通過(guò)這種方式我們可以實(shí)現(xiàn)一個(gè)導(dǎo)航欄的功能: 2.AJAX 方式 Step1.JavaScrpit 發(fā)送異步請(qǐng)求 Step2. 服務(wù)端查詢(xún)數(shù)據(jù)庫(kù),返回?cái)?shù)據(jù) Step3. 服務(wù)端返回 Response Step4. 客戶(hù)端根據(jù)返回的 Response,來(lái)用 Javascript 操作 DOM。 看下面的例子: 當(dāng)我們切換 dropDownList 中的 Item 時(shí),Javascript 發(fā)送異步請(qǐng)求給 Server 端,Server 端返回?cái)?shù)據(jù),然后 Javascript 將數(shù)據(jù)解析出來(lái),拼接了一個(gè) Table,將 Table 呈現(xiàn)在頁(yè)面上。 二、提交 Form 表單的原理1. 代碼 客戶(hù)端代碼: <form id="form1" action="Test.ashx" method="get"> 您的姓名1:<input type="text" name="fname" size="20" /> <input type="submit" name="submit" value="Sumbit"> </form> 服務(wù)端代碼: public void ProcessRequest (HttpContext context){ //Delay for (int i = 0; i < 2; i++) { System.Threading.Thread.Sleep(1000); } //從Requset.Form中獲取fname的值。使用Form獲取請(qǐng)求的鍵值對(duì)的值的前提條件是HTTP request Content-Type 值必須是"application/x-www-form-urlencoded" 或 "multipart/form-data". string fname = context.Request["fname"]; context.Response.ContentType = "text/plain"; //將字符串寫(xiě)入 HTTP 響應(yīng)輸出流。 context.Response.Write("Hello World " + fname); } 2. 將代碼部署到 IIS3. 打開(kāi)站點(diǎn):http://localhost:8003/Test.html
4. 輸入 “Jackson0714” 然后點(diǎn)擊 Sumbit 按鈕頁(yè)面會(huì)重新刷新,顯示 "Hello World Jackson0714" 5. 提交 Form 表單后,頁(yè)面發(fā)送請(qǐng)求和服務(wù)端返回響應(yīng)的流程
6. 通過(guò)抓包,我們可以得到 HTTP Headers瀏覽器發(fā)送 HTTP 給服務(wù)端,采取的協(xié)議是 HTTP 協(xié)議。 在傳輸過(guò)程中,我們可以看下 HTTP Headers。 三、AJAX 提交請(qǐng)求和服務(wù)響應(yīng)的原理1. 代碼客戶(hù)端 HTML 代碼: <!DOCTYPE html> <html lang="en" xmlns="http://www.w3.org/1999/xhtml"><head> <meta charset="utf-8" /> <title></title> <script type="text/javascript" src="Ajax.js"></script> </head><body> <div id="Test" style="background-color:#40eeee"> 您的姓名2:<input type="text" id="testGetName" size="20" /> <button type="button" onclick="testGet();">Ajax Get請(qǐng)求</button> </div> <div id="Test" style="background-color:#ff6a00"> 您的姓名3:<input type="text" id="testPostName" size="20" /> <button type="button" onclick="testPost();">Ajax Post請(qǐng)求</button> </div> <div id="myDiv" /> </body></html> 客戶(hù)端 JS 代碼: var xmlhttp = createRequest(); function testGet() { var fname = document.getElementById("testGetName").value; xmlhttp.open("GET", "Test.ashx?fname=" + fname + "&random=" + Math.random() , true); xmlhttp.onreadystatechange = callback; xmlhttp.send(null);} function testPost() { var fname = document.getElementById("testPostName").value; xmlhttp.open("POST", "Test.ashx?" + "&random=" + Math.random() , true); xmlhttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded;charset=UTF-8"); xmlhttp.onreadystatechange = callback; xmlhttp.send("fname="+fname); } function createRequest() { var xmlhttp; if (window.XMLHttpRequest) { // code for IE7+, Firefox, Chrome, Opera, Safari xmlhttp = new XMLHttpRequest(); } else { // code for IE6, IE5 xmlhttp = new ActiveXObject("Microsoft.XMLHTTP"); } return xmlhttp} function callback() { if (xmlhttp.readyState == 4 && xmlhttp.status == 200) { document.getElementById("myDiv").innerHTML = xmlhttp.responseText; }} 這里有一點(diǎn)需要注意
1. 讓服務(wù)端能夠操作這個(gè)變量,如果定義成局部變量,則服務(wù)端返回 response 時(shí),不能對(duì) xmlhttp 的屬性賦值?;卣{(diào)函數(shù)要求 request 是全局的,才能訪問(wèn)這個(gè)變量和它的屬性值。 2. 定義成全局變量后,可能出現(xiàn)兩個(gè)請(qǐng)求或多個(gè)請(qǐng)求共享同一個(gè)請(qǐng)求對(duì)象。而這個(gè)請(qǐng)求對(duì)象只能存放一個(gè)回調(diào)函數(shù)來(lái)處理服務(wù)器響應(yīng)。當(dāng)服務(wù)器返回兩個(gè)請(qǐng)求的 Response 后,可能會(huì)調(diào)用后指定的回調(diào)函數(shù)。所以可能有兩個(gè)完全不同的服務(wù)器響應(yīng)由同一個(gè)回調(diào)函數(shù)處理,而這可能并不是正確的處理。解決辦法是創(chuàng)建兩個(gè)不同的請(qǐng)求對(duì)象。 服務(wù)端代碼不變。 2. 輸入 “Jackson0714” 然后點(diǎn)擊 Sumbit 按鈕頁(yè)面不會(huì)刷新,在最下面顯示 "Hello World Jackson0714" 3.AJAX 發(fā)送請(qǐng)求和服務(wù)端返回響應(yīng)的流程
4. 通過(guò)抓包,我們可以得到 HTTP Headers瀏覽器發(fā)送 HTTP 給服務(wù)端,采取的協(xié)議是 HTTP 協(xié)議。 在傳輸過(guò)程中,我們可以看下 HTTP Headers:
5.AJAX GET 和 POST 方式區(qū)別AJAX 發(fā)送請(qǐng)求和 POST 發(fā)送請(qǐng)求的代碼如下: //GET方式function testGet() { var fname = document.getElementById("testGetName").value; xmlhttp.open("GET", "Test.ashx?fname=" + fname + "&random=" + Math.random() , true);xmlhttp.onreadystatechange = callback; xmlhttp.send(null);} //POST方式function testPost() { var fname = document.getElementById("testPostName").value; xmlhttp.open("POST", "Test.ashx?" + "&random=" + Math.random() , true); xmlhttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded;charset=UTF-8"); xmlhttp.onreadystatechange = callback; xmlhttp.send("fname="+fname); }
1. 請(qǐng)求的 URL 中,POST 方式可以添加鍵值對(duì),也可以不添加 2.GET 方式中,send 方法傳遞值無(wú)效。對(duì)于 IE 瀏覽器可以忽略 send () 方法的參數(shù)。但是對(duì)于 FireFox,必須提供一個(gè) null 引用,否則回調(diào)行為將不規(guī)律。這是在編寫(xiě)客戶(hù)端腳本時(shí)你會(huì)發(fā)現(xiàn)的一個(gè)跨瀏覽器兼容的問(wèn)題。 3.POST 可以用 send 方法發(fā)送額外信息。發(fā)送的信息存放在 content 中 4.Post 方式需要指定 Request Header 的類(lèi)型。Get 方式不需要指定。 5.GET 方式將參數(shù)暴露在 URL 中,POST 不暴露。
四、XMLHttpRequest 對(duì)象的知識(shí)1.XMLHttpRequest 對(duì)象的方法2.XMLHttpRequest 對(duì)象的屬性
五、JQuery 實(shí)現(xiàn) AJAX下面的代碼實(shí)現(xiàn)了當(dāng)切換 dropDownList 的 item 時(shí),觸發(fā) getWeeklyCalendar 方法,用 JQuery 的類(lèi)庫(kù)方法 $.ajax 來(lái)發(fā)送 AJAX 請(qǐng)求。 客戶(hù)端 JQuery 代碼 function getWeeklyCalendar(name,currentDate,mode){ $.ajax({ type:'POST', url:'weekProcess.php',data:'func=getWeeklyCalender&name='+name+'¤tDate='+currentDate+'& mode='+mode, success:function(data){ paintWeeklyCandler(data); } });} 后臺(tái)成功返回 Response 后,執(zhí)行 paintWeeklyCandler (data) 方法 后臺(tái) PHP 代碼 <?php<br> //定義返回的Response的格式為JSON格式 header('Content-type: text/json');<br> //引入自定義的數(shù)據(jù)庫(kù)連接文件 include 'dbConfig.php';<br> //引入自定義的設(shè)置session的文件 include_once 'session.php'; /* * Function requested by Ajax */ if(isset($_POST['func']) && !empty($_POST['func'])) { switch($_POST['func']){ case 'getWeeklyCalender': getWeeklyCalender($_POST['name'],$_POST['currentDate'],$_POST['mode']); break; case 'getWeeklyStatus': getWeeklyStatus($_POST['name'],$_POST['currentDate'],$_POST['mode']); break; case 'getEvents': getEvents($_POST['date'],$_POST['name']); break; default: break; }} function getWeeklyCalender($name = '',$currentDate = '',$mode = ''){ //邏輯代碼<br> <br> <br> //返回JSON格式的Response echo json_encode(array('result'=>$DaysOfWeekResultsArray)); }<br>?> 六、優(yōu)勢(shì)1. 使用異步方式與服務(wù)器通信,頁(yè)面不需要重新加載,頁(yè)面無(wú)刷新 2. 按需取數(shù)據(jù),減少服務(wù)器的負(fù)擔(dān) 3. 使得 Web 應(yīng)用程序更為迅捷地響應(yīng)用戶(hù)交互 4.AJAX 基于標(biāo)準(zhǔn)化的并被廣泛支持的技術(shù),不需要下載瀏覽器插件或者小程序,但需要客戶(hù)允許 Javascript 在瀏覽器上執(zhí)行 5. 瀏覽器的內(nèi)容和服務(wù)端代碼進(jìn)行分離。頁(yè)面的內(nèi)容全部由 JAVAscript 來(lái)控制,服務(wù)端負(fù)責(zé)邏輯的校驗(yàn)和從數(shù)據(jù)庫(kù)中拿數(shù)據(jù)。
七、缺點(diǎn)1. 安全問(wèn)題:將服務(wù)端的方法暴露出來(lái),黑客可利用這一點(diǎn)進(jìn)行攻擊 2. 大量 JS 代碼,容易出錯(cuò) 3.Ajax 的無(wú)刷新重載,由于頁(yè)面的變化沒(méi)有刷新重載那么明顯,所以容易給用戶(hù)帶來(lái)困擾 —— 用戶(hù)不太清楚現(xiàn)在的數(shù)據(jù)是新的還是已經(jīng)更新過(guò)的;現(xiàn)有的解決有:在相關(guān)位置提示、數(shù)據(jù)更新的區(qū)域設(shè)計(jì)得比較明顯、數(shù)據(jù)更新后給用戶(hù)提示等 4. 可能破壞瀏覽器后退按鈕的正常行為; 5. 一些手持設(shè)備(如手機(jī)、PAD 等)自帶的瀏覽器現(xiàn)在還不能很好的支持 Ajax
八、應(yīng)用場(chǎng)景1. 對(duì)數(shù)據(jù)進(jìn)行過(guò)濾和操縱相關(guān)數(shù)據(jù)的場(chǎng)景 2. 添加 / 刪除樹(shù)節(jié)點(diǎn) 3. 添加 / 刪除列表中的某一行記錄 4. 切換下拉列表 item 5. 注冊(cè)用戶(hù)名重名的校驗(yàn)
九、不適用場(chǎng)景1. 整個(gè)頁(yè)面內(nèi)容的保存 2. 導(dǎo)航 該文章在 2023/10/28 16:23:57 編輯過(guò) |
關(guān)鍵字查詢(xún)
相關(guān)文章
正在查詢(xún)... |