級別: 中級
Ken Ramirez , 創(chuàng)始人, Axsys Technology Group
2008 年 9 月 23 日
學(xué)習(xí)使用原生 JavaScript? 代碼和 PHP 編寫 Asynchronous JavaScript +XML(Ajax)應(yīng)用程序的過程。本文介紹幾個框架和應(yīng)用程序編程接口(API),可以用它們減少開發(fā) Ajax Web應(yīng)用程序所需編寫的代碼量。
PHP已經(jīng)流行很多年了。PHP 通常作為服務(wù)器端腳本語言,用來快速開發(fā)基于 Web 的應(yīng)用程序,而且效果很不錯。實際上,一些最流行的 Web項目(比如 PHP-Nuke、osCommerce 和 Joomla)都是用 PHP 開發(fā)的,它們至今仍然很興旺。
Ajax也已經(jīng)出現(xiàn)了一陣子了,但是直到最近使用 Ajax 技術(shù)開發(fā)的 Web 站點才開始大量增加。Ajax 技術(shù)使 Web 站點或 Web應(yīng)用程序能夠自動地與服務(wù)器通信,而不需要刷新整個頁面。從本質(zhì)上說,Ajax的異步特性使客戶機瀏覽器能夠向服務(wù)器發(fā)送請求或調(diào)用服務(wù)器端的方法。在客戶端,可以使用 JavaScript代碼處理服務(wù)器返回的結(jié)果,然后可以把任何輸出合并到現(xiàn)有的前端 HTML 視圖中,而不需要刷新頁面。在使用 Ajax時,實際上并不使用新的編程語言。實際上,只需組合使用現(xiàn)有技術(shù)。
![]() |
|
PHP和 Ajax 的組合提供一個強大的平臺,可以用來創(chuàng)建具備健壯的特性的 Web 站點或 Web 應(yīng)用程序。本文討論 PHP 和 Ajax的一些用途,研究如何在自己的 Web 應(yīng)用程序中使用它們。在閱讀本文之前,您應(yīng)該充分理解 HTML 和 JavaScript編程。您還應(yīng)該熟悉 PHP 腳本編程語言,雖然也可以使用大多數(shù)其他腳本語言。
在 Ajax 中客戶機/服務(wù)器通信的關(guān)鍵是使用 JavaScript
XMLHttpRequest
對象。大多數(shù)瀏覽器都支持這個對象,包括 Windows? Internet Explorer 5.0 和更高版本、Safari1.2、Mozilla Firefox、Opera 8 和更高版本以及 Netscape 7。為了解釋傳統(tǒng)客戶機/服務(wù)器通信和基于 Ajax的客戶機/服務(wù)器通信之間的差異,下面舉一個例子。按照傳統(tǒng)方式,為了讓客戶機瀏覽器向服務(wù)器發(fā)送需要處理或存儲在數(shù)據(jù)庫中的內(nèi)容,常常使用
POST
方法把客戶端上輸入控件收集的內(nèi)容發(fā)送到服務(wù)器。服務(wù)器使用 PHP(或其他腳本語言)處理這些內(nèi)容,使用數(shù)據(jù)庫讀取或存儲數(shù)據(jù),最后返回嵌入在 HTML 代碼中的結(jié)果。然后,瀏覽器處理 HTML 并向最終用戶顯示一個新頁面。圖 1 描述這個場景。
圖 1. 提交數(shù)據(jù)并接收結(jié)果的傳統(tǒng)過程
通過使用 Ajax,同樣的過程在前端需要的時間更少。其基本思想是讓用戶感覺不必等待頁面更新。實際上,通過使用 Ajax,可以用一個 HTML頁面構(gòu)成整個 Web 應(yīng)用程序,但是不建議這么做。按照傳統(tǒng)方式,如果希望向服務(wù)器提交一個表單,就要設(shè)置表單的動作并把動作類型指定為
POST
。在使用 Ajax 時,實際上并不向服務(wù)器直接提交表單,而是調(diào)用一個 JavaScript 函數(shù)。這個函數(shù)從表單收集數(shù)據(jù)并執(zhí)行檢驗,然后使用
XMLHttpRequest
把數(shù)據(jù)發(fā)送給一個服務(wù)器端函數(shù)。當(dāng)結(jié)果返回客戶機時,客戶機處理結(jié)果并更新需要更新的頁面部分。在這種情況下,頁面
并不
全部地刷新。因此,處理 HTML 所花費的時間更少,性能會更好。圖 2 說明了使用 Ajax 更新頁面與刷新整個頁面之間的細微差別。
圖 2. 提交數(shù)據(jù)并接收結(jié)果的 Ajax 過程
現(xiàn)在看看通過 JavaScript 代碼與服務(wù)器進行通信所需的步驟。首先,定義表單的外觀,見清單 1。
<body> My First Ajax Page <form name="myForm"> Press button to view server time: <input type="button" value="Update" onClick="ajaxFunction();" /> Server Time Is: <input type="text" name="time" /> </form> </body> |
這個表單產(chǎn)生圖 3 所示的輸出。
這個表單沒有做任何真正有用的事,但是它幫助您了解在自己的代碼中的什么地方集成 Ajax。
請注意按鈕上指定的
onClick
事件。這個事件調(diào)用一個名為
ajaxFunction
的 JavaScript 函數(shù)。這里就是 Ajax 中比較有趣的地方。在這個方法中,要執(zhí)行幾個步驟,本節(jié)會逐一解釋這些步驟:
-
創(chuàng)建
XMLHttpRequest
對象的實例。 - 連接要調(diào)用的服務(wù)器端服務(wù)。
- 告訴 Ajax 在服務(wù)器端代碼執(zhí)行完成并返回結(jié)果時應(yīng)該調(diào)用哪個方法。
- 發(fā)送請求。
- 異步地響應(yīng)。
需要創(chuàng)建
ajaxFunction
并提供一個變量來容納創(chuàng)建的
XMLHttpRequest
對象。與任何 JavaScript 方法一樣,按照清單 2 所示定義這個方法。
function ajaxFunction() { var xmlHttp = null; . . . } |
大多數(shù)現(xiàn)代瀏覽器都支持
XMLHttpRequest
對象。但是,Internet Explorer 6 等比較陳舊的瀏覽器要求創(chuàng)建一個 ActiveX 對象來執(zhí)行異步的服務(wù)器調(diào)用。這會產(chǎn)生一個問題:必須判斷正在運行代碼的瀏覽器類型并創(chuàng)建適當(dāng)?shù)膶ο蟆avaScript 代碼通過它的
try/catch
功能提供了一個解決方案。只需以正確的優(yōu)先次序嘗試創(chuàng)建對象,讓
try/catch
塊處理其余的事情。清單 3 給出一個代碼示例。
清單 3. 創(chuàng)建適當(dāng)?shù)膶ο?
function ajaxFunction() { var xmlHttp=null; try { // Firefox, Internet Explorer 7. Opera 8.0+, Safari. xmlHttp = new XMLHttpRequest(); } catch (e) { // Internet Explorer 6. try { xmlHttp = new ActiveXObject("Msxml2.XMLHTTP"); } catch (e) { try { xmlHttp = new ActiveXObject("Microsoft.XMLHTTP"); } catch (e) { return false; } } } } |
可以看到,所有現(xiàn)代瀏覽器都支持創(chuàng)建
XMLHttpRequest
對象。關(guān)于 Microsoft? 是真正支持
XMLHttpRequest
對象,還是使用一個 fa?ade 包裝 ActiveX 實現(xiàn),還有一些爭議。
在同一個 JavaScript 函數(shù)中,創(chuàng)建
XMLHttpRequest
對象之后,使用
XMLHttpRequest
對象的
open
方法打開一個到服務(wù)器端腳本的連接。這個方法有兩個必要參數(shù)和三個可選參數(shù),見表 1。
method |
指定要使用的 HTTP 方法。有效值包括
GET
、
POST
、
PUT
或
HEAD
。
|
url | 指定要調(diào)用的 XML 數(shù)據(jù)或服務(wù)器端 XML Web 服務(wù)的絕對路徑或相對路徑。為了防止跨站點腳本攻擊,Ajax 請求針對的 URL必須使用與包含 Ajax 請求的頁面相同的協(xié)議、主機和端口。盡管一些瀏覽器可能允許任意的URL,但是并非所有瀏覽器都支持這么做。如果需要跨站點通信,必須在服務(wù)器端使用 cURL 或其他方法進行處理。 |
async |
如果希望異步地向服務(wù)器發(fā)送請求,應(yīng)該把這個參數(shù)設(shè)置為 true。true 值還要求設(shè)置
onreadystatechange
屬性,稍后討論這個屬性。把這個參數(shù)設(shè)置為 false 會禁止大多數(shù)瀏覽器接收任何進一步的用戶輸入。如果應(yīng)用程序足夠靈活,能夠在執(zhí)行后端操作的同時繼續(xù)接收輸入,那么最好異步地執(zhí)行操作。
|
user | 指定一個用戶名,用來在執(zhí)行腳本之前對用戶進行身份驗證。只有在腳本要求用戶身份驗證的情況下,才需要這個參數(shù)。 |
password | 指定一個密碼,用來在執(zhí)行腳本之前對用戶進行身份驗證。只有在腳本要求用戶身份驗證的情況下,才需要這個參數(shù)。 |
對于這個示例,代碼只需要執(zhí)行一個
GET
操作,向服務(wù)器上的一個腳本請求時間。還告訴
open
方法我們希望異步地執(zhí)行操作,見清單 4。
function ajaxFunction() { . . . xmlHttp.open("GET", "time.php", true); } |
告訴 Ajax 在服務(wù)器端代碼執(zhí)行完成時應(yīng)該調(diào)用哪個方法
在使用 Ajax 調(diào)用服務(wù)器時,產(chǎn)生的響應(yīng)是通過調(diào)用一個回調(diào)函數(shù)返回的。可以創(chuàng)建并命名一個函數(shù),也可以創(chuàng)建無名的函數(shù)。無論是哪種情況,都需要設(shè)置
XMLHttpRequest
對象的
onReadyStateChange
屬性,讓它知道要使用的回調(diào)函數(shù),見清單 5。
清單 5. 設(shè)置
onReadyStateChange
屬性
function ajaxFunction() { . . . xmlHttp.onreadystatechange=function() { if(xmlHttp.readyState==4) { // Get the data from the server's response. document.myForm.time.value=xmlHttp.responseText; xmlHttp=null; } } } |
可以看到,調(diào)用這個方法之后,它會檢查
readyState
,尋找有效值 4。共有五個有效狀態(tài),見表 2。
0 | 未初始化 |
1 | 正在裝載 |
2 | 裝載完成 |
3 | 交互狀態(tài) |
4 | 已經(jīng)完成 |
這段代碼的基本意思是,“如果狀態(tài)指出操作已經(jīng)完成,就進行處理”。當(dāng)狀態(tài)為已經(jīng)完成時,下一步是用服務(wù)器響應(yīng)更新需要更新的頁面部分。這需要接收賦值給
responseText
屬性的值,這就是服務(wù)器響應(yīng)。最后,通過把
XMLHttpRequest
對象賦值為
null
,停止這個對象。
ajaxFunction
還需要執(zhí)行一個步驟,也就是把請求發(fā)送到服務(wù)器。這需要使用
XMLHttpRequest
對象的
send
方法。如果請求是異步的,這個方法會在發(fā)送請求之后立即返回。如果請求是同步的,這個方法在收到響應(yīng)之后才會返回,這意味著 Ajax 函數(shù)會一直阻塞,直到這個方法返回。
這個方法有一個參數(shù),可以把它設(shè)置為 null 或許多其他值。例如,可以傳遞一個
DOMDocument
對象、
InputStream
或
String
。如果請求方法是
POST
,這個值就用作 HTTP 請求體。完成的
ajaxFunction
應(yīng)該與清單 6 相似。
function ajaxFunction() { var xmlHttp=null; try { // Firefox, Internet Explorer 7. Opera 8.0+, Safari xmlHttp = new XMLHttpRequest(); } catch (e) { // Internet Explorer 6. try { xmlHttp = new ActiveXObject("Msxml2.XMLHTTP"); } catch (e) { try { xmlHttp = new ActiveXObject("Microsoft.XMLHTTP"); } catch (e) { alert("Your browser does not support AJAX!"); return false; } } } xmlHttp.open("GET", "time.php", true); xmlHttp.onreadystatechange=function() { if(xmlHttp.readyState==4) { // Get the data from the server's response. document.myForm.time.value=xmlHttp.responseText; xmlHttp=null; } } xmlHttp.send(""); } |
因為 Ajax 在本質(zhì)上是異步的,所以必須注意并發(fā)性并了解處理次序。在發(fā)出多個 Ajax 調(diào)用并以出乎意料的次序接收響應(yīng)時,這尤其重要。一般假設(shè)次序是無法意料的。
有時候,服務(wù)器響應(yīng)需要以 XML 文檔的形式返回給客戶機。在這些情況下,可以使用
XMLHttpRequest
對象的
responseXML
屬性接收數(shù)據(jù)。清單 7 給出一個返回 XML 文檔的 PHP 腳本示例。
<?php $result = getRecordSet($_GET['query']; echo '<?xml version="1.0" encoding="ISO-8859-1"?>' . '<car>'; while($row = mysql_fetch_array($result)) { echo "<make>" . $row['make'] . "</make>"; echo "<model>" . $row['model'] . "</model>"; echo "<year>" . $row['year'] . "</year>"; echo "<description>" . $row['description'] . "</description>"; } echo '</car>'; ?> |
這段代碼創(chuàng)建一個 XML 文檔(由
'<?xml version="1.0" encoding="ISO-8859-1"?>'
表示),然后發(fā)送響應(yīng)的其余部分。客戶端代碼必須先從
responseXML
屬性中取出 XML 文檔,使用 Document Object Model(DOM)解析數(shù)據(jù),然后通過修改頁面上現(xiàn)有的適當(dāng)字段在頁面上顯示數(shù)據(jù)。清單 8 演示這些步驟。
清單 8. 處理 XML 文檔的 JavaScript 代碼
function stateChanged() { if(xmlHttp.readyState==4) { xmlDoc = xmlHttp.responseXML; document.getElementById("make").innerHTML = xmlDoc.getElementsByTagName("make")[0].childNodes[0].nodeValue; document.getElementById("model").innerHTML = xmlDoc.getElementsByTagName("model")[0].childNodes[0].nodeValue; document.getElementById("year").innerHTML = xmlDoc.getElementsByTagName("year")[0].childNodes[0].nodeValue; document.getElementById("description").innerHTML = xmlDoc.getElementsByTagName("description")[0].childNodes[0].nodeValue; } } |
您可能會注意到,為了在前端實現(xiàn) Ajax 功能,服務(wù)器端 PHP 代碼并不需要任何特殊的東西。實際上,可以用任何語言編寫服務(wù)器端腳本,只要能夠從Web 服務(wù)器調(diào)用它并把結(jié)果返回給客戶機。但是,出于幾個目的,希望擴展 Ajax來實現(xiàn)其他功能。例如,許多庫提供了外觀更好的前端控件,可以實現(xiàn) Web 2.0 所需的效果。這些庫大多數(shù)是用 JavaScript代碼編寫的,并提供了可以減少編寫前端所需的 JavaScript 代碼量的特性和 API。另外,這些庫大多數(shù)使用 JavaScriptObject Notation(JSON),這是一種目前在因特網(wǎng)上廣泛使用的輕量數(shù)據(jù)交換格式。下面是可能對您有幫助的一些庫:
- Prototype
- Script.aculo.us
- Dojo
- jQuery
Prototype提供用來開發(fā)動態(tài) Web 應(yīng)用程序的類驅(qū)動的 JavaScript 代碼。另外,Prototype 框架還提供一個全局 Ajax對象,這個對象使 Ajax 功能更容易編寫、效果更好、更容易處理。另外,通過使用這個框架進行 Ajax開發(fā),就不再需要處理跨瀏覽器問題。只需在一次調(diào)用中指定目標(biāo) URL、HTTP 方法(
POST
或
GET
)和響應(yīng)回調(diào)函數(shù)等等。
Script.aculo.us是另一個流行的 JavaScript 框架,它提供一些出色的用戶界面控件。這個框架還提供了一些執(zhí)行 Ajax 功能的控件。甚至還有一個Google 風(fēng)格的自動補齊文本控件,可以用它收集用戶輸入的文本。Ajax功能允許輕松地指定查詢的服務(wù)器端目標(biāo)。產(chǎn)生的響應(yīng)用來向最終用戶顯示服務(wù)器返回的字符串集。
Dojo工具集是一個開放源碼的 JavaScript 和 Ajax 框架,它速度快和文件小(只有 25 KB),因此很受歡迎。在 Ajax方面,Dojo 提供了用來發(fā)送和接收異步服務(wù)器調(diào)用和響應(yīng)的 API。在服務(wù)器端不需要修改任何代碼。對于任何 Ajax 調(diào)用,您的 PHP代碼仍然可以做出響應(yīng)。
jQuery 的優(yōu)點是簡化了在頁面上搜索元素的機制,并支持在運行時動態(tài)地添加新函數(shù)、特性和格式。它還提供一些與眾不同的 Ajax 特性,支持在 Web 頁面上提供 Ajax 交互。
既然了解了基本概念,現(xiàn)在就來討論如何擴展 PHP 來支持 Ajax。從 PHP 的角度來看,擴展 Ajax 功能并不僅僅是重寫
XMLHttpRequest
(XHR)訪問代碼。這還涉及以更簡單更直觀的方式提供前端服務(wù),然后通過它們訪問用 PHP編寫的后端服務(wù)。應(yīng)該包括從前端執(zhí)行后端服務(wù)、訪問數(shù)據(jù)庫、執(zhí)行后端網(wǎng)絡(luò)服務(wù)等特性。我在市場上看到的一些框架允許開發(fā)人員用后端語言編寫代碼,然后由框架創(chuàng)建前端 JavaScript 代碼。開發(fā)人員告訴框架必須調(diào)用哪些后端方法,框架就會用 JavaScript 代碼編寫前端fa?ade,這些代碼可以分配 XHR 對象、發(fā)送請求、接收響應(yīng),然后把響應(yīng)傳遞給您選擇的函數(shù),甚至把輸出直接賦值給您選擇的 HTML元素。這種框架設(shè)計思想可以減少必須編寫的 JavaScript代碼。希望為其提供函數(shù)的所有元素都可以被覆蓋,可以把它們連接到在發(fā)生指定的前端事件時做出響應(yīng)的后端方法。下面是值得研究的一些框架:
- PHP AJAX
- PHP-Ext
- ExtPHP
PHP AJAX 允許開發(fā)人員用自己的類擴展 PHP 類。然后,只需在調(diào)用 PHP 文件時調(diào)用一個初始化方法,它會替您生成必需的前端 XHR 代碼。前端事件必須調(diào)用一個與 PHP 類同名的 JavaScript 函數(shù)。代碼與清單 9 相似。
class ajax_app extends phpajax { function input() { } function loading() { } function main() { } } |
調(diào)用覆蓋的方法執(zhí)行 Ajax 生命周期中的各種任務(wù)。例如,如果在前端執(zhí)行一個操作,就調(diào)用后端類的
main()
方法處理這個操作。在前端收集的所有輸入都傳遞給
input()
方法。
PHP-Ext提供一個支持 PHP 4 和 5 的庫,這個庫提供大量前端用戶界面控件。這些控件的底層代碼實際上是由 Ext JS提供的,但這個框架的特色是開發(fā)人員不需要提供 JavaScript 來操作前端控件。相反,與控件的所有交互都是通過用 PHP編寫的后端服務(wù)來執(zhí)行的。在需要時,根據(jù)指定的事件調(diào)用 PHP 代碼。當(dāng)發(fā)生指定的事件時,就會調(diào)用對應(yīng)的 PHP 代碼。按照這種方式,可以從PHP 代碼幾乎直接地填寫網(wǎng)格和其他控件的內(nèi)容。
用PHP 編寫的另一種 Ext JS 包裝器是 ExtPHP(不要與前面提到的 PHP-Ext 混淆)。按照這個項目的開發(fā)負責(zé)人的說法,可以使用ExtPHP 編寫侵入式和非侵入式 JavaScript 代碼,編程方式與使用 Ext JS 時相同。這個框架的優(yōu)點是允許 PHP編輯器探測未知的、拼寫錯誤的或使用不當(dāng)?shù)姆椒ǎ@樣就不必在 Web 瀏覽器中調(diào)試 JavaScript 代碼。ExtPHP的設(shè)計思想是生成可以從 PHP 腳本調(diào)用的 PHP 類。在實例化一個對象時,會把對應(yīng)的 JavaScript代碼存儲在一個內(nèi)部緩沖區(qū)中。如果調(diào)用一個對象的方法,代碼也被添加到內(nèi)部緩沖區(qū)中。準(zhǔn)備好所有 JavaScript 代碼之后,只需調(diào)用一個方法
jsrender()
。還可以通過調(diào)用 ExtPHP 函數(shù)在輸出中添加內(nèi)容,這樣就可以在輸出中直接添加 JavaScript 代碼。
本文介紹了如何編寫基于 Ajax 的前端代碼,以及如何把前端代碼和后端 PHP 腳本結(jié)合起來。還介紹了一些最新的框架,可以使用這些框架大大加快Ajax Web 應(yīng)用程序的創(chuàng)建。通過結(jié)合使用這些框架、Ajax 和 PHP,可以編寫出外觀優(yōu)美、功能豐富的 Web應(yīng)用程序。實際上,如果您掌握了這些新技術(shù),就會覺得離不開它們了。
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯(lián)系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
