使用jQuery和PHP構(gòu)建一個受Ajax驅(qū)動的Web頁面
大多數(shù) PHP 開發(fā)人員都是以老式的方法學(xué)習(xí)技能。他們一般先學(xué)習(xí)如何定義和構(gòu)建簡單的 PHP 頁面,然后再了解如何將這些頁面連接到簡單的 MySQL 表,于是就可以由此進(jìn)行自己的開發(fā)了。隨著技能水平的提高,他們還逐漸學(xué)會了如何創(chuàng)建更為復(fù)雜的 PHP 功能,以及如何連接 MySQL 內(nèi)的表并執(zhí)行其他高級任務(wù)。
在這個過程中,他們有可能還會掌握一些客戶端技能來將 Web 應(yīng)用程序投入使用。也有可能學(xué)會有關(guān) XHTML 或 CSS 甚至一些 JavaScript 編程的知識。隨著所參與項(xiàng)目的種類的增多,他們甚至有機(jī)會接觸到 Ajax 以便為您的 Web 應(yīng)用程序賦予 Web 2.0 或 “桌面” 的感覺。不過,如果您初次使用 Ajax 的經(jīng)驗(yàn)與我類似的話,您可能已經(jīng)做了太多的工作 — 手動實(shí)現(xiàn)各種函數(shù)、經(jīng)歷創(chuàng)建一個受 Ajax 驅(qū)動頁面的艱難過程。
對于某些人而言,Ajax 仍是個謎。它似乎是 Web 開發(fā)/交互社區(qū)中的 “酷小孩(cool kid)” 和 “壞小孩(bad boys)” 才會做的事情,而他們則沒有時間和耐心或者能力去了解并使用它。這真是個遺憾,因?yàn)楹芏嗫蛻舻拇_喜歡添加 Ajax 風(fēng)格的功能 — 它讓 Web 應(yīng)用程序更容易使用。如果您是這些 PHP 開發(fā)人員中的一員,也請不要害怕:讀完本文,您所掌握的知識足以讓您成為一名真正的 Ajax 專業(yè)人士。
本文展示了如何使用 jQuery 來向 PHP Web 應(yīng)用程序輕松添加 Ajax 功能。我們將使用 PHP 和 MySQL 構(gòu)建一個簡單的 Web 應(yīng)用程序 — 一個包含名字和電話號碼的電話本。這個應(yīng)用程序具備預(yù)期的所有標(biāo)準(zhǔn)功能 — 比如可以查找名字或電話號碼、具有 MySQL 表等。接下來,還將向應(yīng)用程序添加 jQuery,以便能夠在鍵入時實(shí)時查找名字和電話號碼。在完成上述任務(wù)后,您也就具備了有關(guān) jQuery 及 Ajax 的充足的基礎(chǔ)知識。
何為 Ajax?
描述 Ajax 的最佳方法是將其與傳統(tǒng)方式進(jìn)行對比。大多數(shù) Web 頁面和應(yīng)用程序都在同步模式下工作。單擊一個鏈接或表單的提交 按鈕后,請求就被發(fā)送給服務(wù)器,而此服務(wù)器之后會處理該請求并發(fā)送回一個響應(yīng)??偨Y(jié)此模型的最好方法是 “單擊、等候、查看”。這就是您所熟知的一個永不終止的漂洗-和-重復(fù)(rinse-and-repeat)的循環(huán)過程。換言之,如果頁面需要經(jīng)常顯示被更新的信息,那么就必須放上某類自動刷新 hack,或者是讓用戶刷新或單擊一個鏈接執(zhí)行刷新。
Ajax 改變了這一切。Ajax 中的第一個字母 A 代表的是 異步。Ajax 允許以任何一種編程語言創(chuàng)建頁面,然后用來自數(shù)據(jù)庫或其他后端服務(wù)器過程的信息刷新該頁面的不同部分。比如,假如說您有一個電子商務(wù)站點(diǎn),上面顯示了所銷售的產(chǎn)品。在每個產(chǎn)品頁面,都有幾個常見項(xiàng)目:標(biāo)題、銷售說明、縮略圖圖片、庫存數(shù)量。
假如,您想讓網(wǎng)站的訪問者能夠獲得庫存數(shù)量的最新信息。您就可以添加一個 Ajax 函數(shù),該函數(shù)能運(yùn)行包含 MySQL 查詢的一個單獨(dú)的 PHP 頁面,然后就可重新填充原始頁面上的信息,無需用戶輸入,也不必考慮事件的單擊-等待-查看模式的同步性。
Ajax 中的 j 代表的是 JavaScript,它是所有行為的驅(qū)動力。這既是好事也是壞事 — 好的一面是由于是客戶端代碼,所以它是可移植的,而且不會影響到服務(wù)器;對 PHP 開發(fā)人員而言不好的一面是它完全不同于他們所習(xí)慣使用的那個環(huán)境。這就需要像 jQuery 這樣的工具和框架來大大簡化您與 Ajax 交互的方式,加快代碼完成的進(jìn)度。
最后的兩項(xiàng):+ 和 x 又代表什么呢?它們代表的是 及 XML,不過,XML 部分并不確切。大量 Ajax 應(yīng)用程序在沒有任何 XML 代碼時仍工作得很好:它們只來回傳遞 HTML,甚至是純文本。更準(zhǔn)確的說法是讓 x 代表 XMLHttpRequest,因?yàn)榭墒褂迷搶ο笤诤笈_檢索數(shù)據(jù),而不會干擾現(xiàn)有頁面的顯示或行為。
何為 jQuery?
jQuery 是 John Resig 創(chuàng)建的一種輕量的 JavaScript 庫,在 2006 年早期發(fā)布于 Internet。它是免費(fèi)的開源軟件,具有 Massachusetts Institute of Technology (MIT) 和 GNU General Public License 的雙重許可。由于它簡單直觀,因此贏得了開發(fā)界很多人的擁護(hù)。
那么它為何如此流行呢?因?yàn)樗峁┝艘环N簡單易用的庫,簡化了 JavaScript,因此任何人(沒錯,甚至一個徹徹底底的后端程序員)無需艱苦的工作就能創(chuàng)建非凡的效果。您可以進(jìn)行 Document Object Model (DOM) 元素選擇、修改和處理 CSS、使元素更加吸引人以及處理 Ajax。所有這些功能性的實(shí)現(xiàn)都來自于一個 JavaScript 文件,該文件可從 jQuery 站點(diǎn)下載(參見 參考資料)。
下載 jQuery 之后,通過包括進(jìn)一個簡單的 ﹤script﹥ 標(biāo)記就可以將其添加到任何的 HTML 或 PHP 文件:
﹤script type="text/javascript" src="/path/to/jquery.js"﹥﹤/script﹥ |
假設(shè),您有一個非常簡單卻很煩人的任務(wù)要完成 — 需要很多手動操作,比如在您站點(diǎn)上的每個表單標(biāo)簽?zāi)┪蔡砑右粋€冒號(:)。您可以遍歷并尋找每個表單標(biāo)簽并在每行的末尾添加一個冒號,您也可以部署如下的 jQuery 代碼:
清單 1. 使用 jQuery 添加一個冒號
﹤script type="text/javascript"﹥ $(document).ready(function(){ $("label").append(":"); }); ﹤/script﹥ |
此函數(shù)很簡單:它將一直等待,直到頁面準(zhǔn)備好并全部加載($(document).ready() 部分)完畢,這時將運(yùn)行一個匿名函數(shù),該函數(shù)尋找所有 DOM label 元素,然后向所找到的文本的末尾追加一個冒號。$() 函數(shù)的功能是允許以其本地名字訪問 DOM 元素,這就讓此接口成為了已經(jīng)熟悉 DOM 的那些開發(fā)人員的最佳選擇。
當(dāng)然,用 jQuery 還能做很多其他的事情,這只是一個好的開端。借助一個簡單的內(nèi)置函數(shù),jQuery 可以確保您的代碼能夠工作,因?yàn)樗鼤却撁婕虞d。有了另一行代碼,就能對代碼所找到的所有 DOM label 元素進(jìn)行徹底更改,所有都在客戶機(jī)內(nèi)進(jìn)行,而無需乏味地遍歷所有標(biāo)記并在那里進(jìn)行更改。
#p#
創(chuàng)建一個簡單的應(yīng)用程序:一個電話本
有了 jQuery 的基本知識之后,我們就可以開始用 PHP 和 MySQL 構(gòu)建一個簡單的電話本應(yīng)用程序了。這個應(yīng)用程序包含三個部分:
◆一個 MySQL 表,用來保存人名和電話號碼
◆具有搜索表單的 index.php 文件
◆用來查詢數(shù)據(jù)庫表的 find.php 頁面
我們將依次構(gòu)建這些元素。
創(chuàng)建數(shù)據(jù)庫表
在 MySQL 內(nèi)創(chuàng)建數(shù)據(jù)庫表可能是最簡單的部分。我們希望此應(yīng)用程序是一個包含有最少量信息的表 — 比如,一個 ID(表的鍵)、一個名字字段以及一個電話號碼字段。最后這兩個字段可以是字母數(shù)字,所以將使用 varchar() 函數(shù)。我們將創(chuàng)建 ID 字段作為一個 autoincrement primary key。將此表稱為目錄 并使用如下的 Structured Query Language (SQL) 代碼來創(chuàng)建它:
清單 2. 使用 SQL 創(chuàng)建目錄表
CREATE TABLE `directory` ( `id` INT NOT NULL AUTO_INCREMENT , `name` VARCHAR( 64 ) NOT NULL , `phone` VARCHAR( 16 ) NOT NULL , PRIMARY KEY ( `id` ) ) TYPE = MYISAM ; |
正如您所見,這里沒有什么復(fù)雜的。實(shí)際上,之后您將有大量機(jī)會自己更新這個應(yīng)用程序。擴(kuò)展此應(yīng)用程序的一種方式是添加一個關(guān)鍵字或地址字段,而二者均能讓您進(jìn)一步精煉搜索。不過,現(xiàn)在,我們還是先從簡單的開始吧。
創(chuàng)建了該表之后,需要填充它??梢允褂?phpMyAdmin 或命令行來輸入一個名字和電話號碼。也可以使用如下的 SQL 指令集:
清單 3. 使用 SQL 填充此表
insert into `directory` (name,phone) values ('Tom Smith', '512-555-0111'); insert into `directory` (name,phone) values ('Bill Smith', '512-555-0112'); insert into `directory` (name,phone) values ('John Smith', '512-555-0113'); insert into `directory` (name,phone) values ('Jane Smith', '512-555-0114'); insert into `directory` (name,phone) values ('Sara Smith', '512-555-0115'); |
輸入了這些值之后,如果從命令行的目錄操作運(yùn)行一個 select * 或單擊 phpMyAdmin 內(nèi)的 Browse ,請確保能夠獲得一個記錄列表。
創(chuàng)建 index.php 文件
接下來,為應(yīng)用程序創(chuàng)建一個簡單的主頁。此頁面是一個 PHP 文件,稱為 index.php,但此時它包含最多的仍是 HTML 代碼。當(dāng)完成了 find.php 文件后(下一步),我們還會返回來完成這一代碼塊。
此刻,所需做的就是創(chuàng)建一個包含表單的骨架 HTML 文件。表單內(nèi)的每個元素均包含一個惟一的 ID,因?yàn)槲覀兿胍軌蚴褂?jQuery 標(biāo)識每一塊。
清單 4. 包含表單的 HTML 文件
﹤html﹥ ﹤head﹥ ﹤title﹥Welcome!﹤/title﹥ ﹤/head﹥ ﹤body﹥ ﹤h1﹥Search our Phone Directory﹤/h1﹥ ﹤form id="searchform" method="post"﹥ ﹤div﹥ ﹤label for="search_term"﹥Search name/phone﹤/label﹥ ﹤input type="text" name="search_term" id="search_term" /﹥ ﹤input type="submit" value="search" id="search_button" /﹥ ﹤/div﹥ ﹤/form﹥ ﹤div id="search_results"﹥﹤/div﹥ ﹤/body﹥ ﹤/html﹥ |
上述代碼中有兩點(diǎn)應(yīng)該會立即引起您的注意。其一,沒有動作與此表單相關(guān)聯(lián)。這沒關(guān)系:請記住,此表單將不會遵循傳統(tǒng)的 “單擊、等待、查看” 的同步模式。相反,我們將會添加能夠監(jiān)視 search_term 字段內(nèi)的用戶動作的功能。
應(yīng)該注意到的第二點(diǎn)是 search_results DOM 元素 — 表單下面的空白元素。這個 DOM 元素將會包含從搜索中獲得的所有響應(yīng)。在對此進(jìn)行深入研究之前,讓我們先來創(chuàng)建 find.php 頁面。
#p#
創(chuàng)建 find.php 文件
find.php 文件是所有操作發(fā)生的地方。在此文件內(nèi),應(yīng)用程序連接到數(shù)據(jù)庫并針對此目錄表運(yùn)行查詢。
find.php 文件的第一部分包含連接信息。出于本文的目的考慮,我將該信息嵌入到了此文件。對于大多數(shù)開發(fā)人員而言,此信息將會處于一個附帶的或必需的文件內(nèi),或是作為一個更大的框架的一部分。
清單 5. 創(chuàng)建 find.php 文件
﹤?php define(HOST, "your.host.here"); define(USER, "your-user-name"); define(PW, "your-password"); define(DB, "your-db-name"); $connect = mysql_connect(HOST,USER,PW) or die('Could not connect to mysql server.' ); mysql_select_db(DB, $connect) or die('Could not select database.'); |
接下來,將會從此 index.php 文件內(nèi)的表單獲得一個搜索詞。對該搜索詞進(jìn)行一些簡單處理,然后將該值插入到數(shù)據(jù)庫內(nèi)。我選擇使用 strip_tags() 和 substr() 函數(shù)來刪除搜索詞內(nèi)的所有 HTML 標(biāo)記并對之進(jìn)行簡化。進(jìn)行這類預(yù)處理不失為一個好的做法 — 不能百分之百相信用戶的輸入。
實(shí)際上,當(dāng)具有了一個清晰的搜索詞后,就可以通過 mysql_escape_string() 運(yùn)行它,這可進(jìn)一步消除可能會破壞數(shù)據(jù)庫的其他陷阱(比如,單引號)。
$term = strip_tags(substr($_POST['search_term'],0, 100));
$term = mysql_escape_string($term);
現(xiàn)在,構(gòu)建 SQL 語句。我們希望從此目錄表能夠檢索到匹配搜索詞的所有名字和電話號碼。使用 LIKE 讓搜索詞能匹配名字和電話這兩個字段,然后使用 mysql_query() 運(yùn)行此查詢。
清單 6. 構(gòu)建 SQL 語句
$sql = "select name,phone from directory where name like '%$term%' or phone like '%$term%' order by name asc"; $result = mysql_query($sql); |
運(yùn)行了此查詢后,可以打印結(jié)果。初始化一個 $string 變量來保存結(jié)果,然后使用 mysql_num_rows() 檢查是否得到了任何結(jié)果。如果沒有獲得針對此搜索詞的結(jié)果,可以將 $string 設(shè)置為等于 “No matches!”。如果的確獲得了結(jié)果,可打印結(jié)果集內(nèi)的每個名字和電話號碼。在過程的末尾,使用 echo 命令打印整個字符串:
清單 7. 使用 echo 命令打印字符串
$string = ''; if (mysql_num_rows($result) ﹥ 0){ while($row = mysql_fetch_object($result)){ $string .= "﹤b﹥".$row-﹥name."﹤/b﹥ - "; $string .= $row-﹥phone."﹤/a﹥"; $string .= "﹤br/﹥\n"; } }else{ $string = "No matches!"; } echo $string; ?﹥ |
當(dāng)然,這個 PHP 功能本身就十分有用,但是現(xiàn)在,這一點(diǎn)沒有突出體現(xiàn)出來。需要能夠?yàn)榇四_本提供一個搜索詞。在下一節(jié),我們將實(shí)現(xiàn)這一目的。
向 index.php 添加 jQuery
至此,我們得到的是一對普通的 PHP 頁面和一個簡單的 MySQL 表。當(dāng)添加了 jQuery 后,這個普通的應(yīng)用程序就會變成一個新穎的、受 Ajax 驅(qū)動的應(yīng)用程序,它將更類似于 Mac OS X 上的 Spotlight 或 Google Desktop Search 這樣的桌面搜索應(yīng)用程序。
現(xiàn)在,打開 index.php 文件并確保添加了對最新下載的 jquery.js 文件的調(diào)用。
﹤script src="./jquery.js"﹥﹤/script﹥
接下來,創(chuàng)建一個簡單的函數(shù)來阻止搜索表單表現(xiàn)得像典型的表單那樣。(使用 preventDefault() 函數(shù)實(shí)現(xiàn)此目的)。將所有 Submit 按鈕和 key-up 事件(即在通過鍵盤鍵入字符時發(fā)生的事件)重新指向到一個將要創(chuàng)建的新函數(shù),稱為 ajax_search()。
清單 8. 創(chuàng)建函數(shù)以阻止搜索表單表現(xiàn)得像典型的表單那樣
﹤script type='text/javascript'﹥ $(document).ready(function(){ $("#search_results").slideUp(); $("#search_button").click(function(e){ e.preventDefault(); ajax_search(); }); $("#search_term").keyup(function(e){ e.preventDefault(); ajax_search(); }); }); |
您注意到我們是如何使用 slideUp() 函數(shù)來暫時隱藏 search_results DOM 元素的嗎?以及又是如何使用 $() 函數(shù)來按名字引用該 DOM 元素?如果您十分熟悉 CSS,那么 jQuery 方式就十分直觀和自然了。比如,假設(shè)有一個具有惟一 ID search_results 的 DOM 元素,您就可以使用 $("#search_results") 來引用它。就這么簡單。
另外還注意到,任何時候,任何人單擊了 Search 或在 search_term 字段鍵入一個字符,一個匿名函數(shù)都會阻止默認(rèn)行為的發(fā)生并會將 應(yīng)用程序流程重新指向到 ajax_search() 函數(shù),該函數(shù)我們接下來將會構(gòu)建。
ajax_search() 函數(shù)十分簡單。我們想要顯示 DOM 元素 search_results(之前已經(jīng)將其隱藏)、獲得 search_term 輸入字段的值、將該值傳遞給一個異步運(yùn)行 find.php 文件的函數(shù)($.post()),然后等待響應(yīng)。當(dāng)響應(yīng)到來后(還記得么,我們已經(jīng)確保了該 find.php 將會返回某種響應(yīng),即便在沒有匹配的情況下也是如此),jQuery 用該響應(yīng)填充 search_results DOM 元素。
清單 9. ajax_search() 函數(shù)
function ajax_search(){ $("#search_results").show(); var search_val=$("#search_term").val(); $.post("./find.php", {search_term : search_val}, function(data){ if (data.length﹥0){ $("#search_results").html(data); } }) } ﹤/script﹥ |
所有系統(tǒng)都就緒后,就可以鍵入一個請求并查看此搜索引擎的實(shí)際工作情況了,每個 key-up 事件都會處理記錄。它在單擊 Submit 時也能工作。比如,在圖 1 中,如果在搜索字段內(nèi)鍵入字母 a,應(yīng)用程序就會返回 Jane 和 Sara Smith 這兩條記錄,因?yàn)檫@兩個名字中都包含此字母。
圖 1. 運(yùn)行中的受 Ajax 驅(qū)動的搜索
結(jié)束語
當(dāng)然,針對此應(yīng)用程序還有很多工作可做。比如,可以添加一個關(guān)鍵字字段,然后允許按關(guān)鍵字搜索?;蛘撸梢宰屆總€人的記錄包含針對其所擅長的不同領(lǐng)域的標(biāo)記或關(guān)鍵字。此后,如果您在項(xiàng)目中遇到問題,就能夠通過資源查找來找到能夠幫助您的人。此外,還可以添加一個電子郵件字段、一個生日字段 — 無論什么都可以 — 然后擴(kuò)展搜索參數(shù)。
關(guān)鍵的一點(diǎn)是此應(yīng)用程序的 jQuery 部分并不關(guān)心在后端發(fā)生的事情。它所知道的就是將一個搜索詞傳遞給一個稱為 find.php 的文件。find.php 文件并不知道也不關(guān)心它從一個 jQuery 函數(shù)接收指令。它所關(guān)注的是只要搜索詞來自于一個正常的表單提交過程,它就使用該數(shù)據(jù)來完成查詢,然后返回匹配該搜索詞的那些記錄。
【編輯推薦】