從開始構建動態 Web 應用程序起,開發人員一直都是使用傳統分頁技術。每當需要顯示大量的數據時,都要使用分頁技術來每次顯示一部分數據。用戶使用 Next 或 Previous 按鈕從一個數據集或頁面導航到另一個數據集或頁面。
如今,傳統分頁技術的一些變體也得到應用。有些是向用戶顯示 First、Previous、Next 和 Last 按鈕,有些是使用數字,還有一些則結合使用按鈕和數字。分頁的概念可以幫助用戶和服務器有效地處理大量的數據。
然而,最近 Ajax 的盛行卻改變了開發人員設計和構建 Web 應用程序的方式。通過使用 Ajax,可以構建外觀和行爲更接近於傳統桌面應用程序的 Web 應用程序。有些開放源碼和商業 JavaScript/Ajax 框架和庫提供了直接可用的小部件(widget),使得 Ajax 模型更易於實現。開發人員可以使用這些小部件輕鬆地爲 Web 應用程序添加豐富的特性和功能。
其中一個那樣的框架就是 Rico。在本文中,我將簡要地介紹這個開放源碼的客戶端 JavaScript 框架,然後着重描述它的一個小部件,即 LiveGrid。正如本文要演示的那樣,可以通過實現 LiveGrid 來替代 Web 應用程序中傳統的分頁模型。
Rico 庫是一個 JavaScript 文件,可以將這個庫包括在任何 Web 頁面中,以便使用豐富的特性和小部件。這個庫處理很多複雜的實現細節,包括跨瀏覽器的兼容性,使您得以心無旁騖地創建頁面功能。
Rico 特性或小部件使用起來很簡單:只需編寫幾行代碼將那個特性或小部件集成到一個給定頁面上。例如,Rico 爲將 Ajax 支持添加到 Web 頁面中提供了一個非常簡單的接口。只需添加 5 到 6 行 JavaScript 代碼,就可以將 Ajax 功能添加到 Web 頁面中,然後,就可以向服務器發出 Ajax 請求,並處理來自服務器的響應。無需直接與 XmlHttpRequest
JavaScript 對象打交道,這一切都可以實現。
通過 Rico,將拖放之類的可視化效果添加到 Web 頁面也很容易。通過 Rico 庫,可以將任何 HTML 或 JavaScript 對象定義爲 draggable(可拖放的) 或一個 drop zone(拖放區)。這樣定義之後,就可以在頁面上拖動可拖放對象,並將其放入一個或多個用戶定義的拖放區。Rico 自動處理該功能的所有實現細節,所以只需編寫幾行代碼。
如果使用 Rico,那麼添加淡入、動畫縮放和位移、旋轉等動畫效果也是非常簡單的。最流行的一個 Rico 小部件就是 Accordion,它顯示一組可摺疊的抽屜。每個抽屜有一個抽屜標題和一個內容區。單擊一個抽屜標題就可以顯示那個抽屜的內容,同時也隱藏其他抽屜中的內容。另一個非常流行的小部件是 LiveGrid,本文的後面將着重講到這個小部件。
圖 1 中的 LiveGrid 是一個可滾動的信息表,每當用戶單擊滾動條,表中的數據就動態更新。這個表被連接到一個活動的數據源,對這個表的更新是藉助 Ajax 完成的。
LiveGrid 顯示一個可滾動的包含 20 部影片的列表。每當用戶單擊滾動條,表的內容就隨之更新,顯示新的一組影片。當需要新的一組數據時,Rico 對服務器發出 Ajax 調用。它使用緩衝技術,以取得更好的性能,並使滾動看上去更爲流暢。因此,可能並不是每次單擊滾動條都會導致 Ajax 請求。Rico 首先使用緩衝區中的數據來更新網格,當用光了緩衝區中所有的數據時,才發出 Ajax 請求。圖 2 顯示了用戶單擊一次滾動條後 LiveGrid 看上去的樣子。LiveGrid 還支持列排序。如果網格中實現了排序,那麼用戶可以單擊列名,然後對這個列進行排序。
作爲一個學習的例子,我將展示如何創建 Movies LiveGrid above。您需要從 Rico 主頁下載 download rico.js 和 prototype.js。注意,Rico 庫使用了另一個開放源代碼框架 Prototype 中的特性,因此這裏需要 prototype.js。此外,還需要一個 Web 應用服務器,用於處理來自 Rico 的 Ajax 調用。對於這個例子,我將使用 Apache Tomcat 6.0。
可以從編寫這個例子的客戶端代碼開始。首先要做的是將 rico.js 和 prototype.js 庫包括在頁面中。假設這兩個庫文件與 HTML 文件在同一個目錄中,清單 1 展示瞭如何將這兩個庫包括在頁面中。
<script src="prototype.js"></script> <script src="rico.js"></script> |
接下來,添加一個佔位符,用於容納顯示圖 1 中文本 "Showing 1 - 5 of 20 Movies" 的標籤。每當用戶單擊滾動條,這個標籤就會更新。
<div id="showingLabel" >Showing 1 - 5 of 20 Movies</div> |
然後,添加顯示圖 1 中列名(例如 Number、Title、Year)的 LiveGrid 標題。
<table cellspacing="0" cellpadding="0" width="400"> <tr> <th bgcolor="#999999" width="30">#</th> <th bgcolor="#999999" width="310">Title</th> <th bgcolor="#999999" width="60">Year</th> </tr> </table> |
最後,可以創建 Rico 用於顯示影片數據的表。用下面代碼創建的表有 6 個行,3 個列。表中每隔一行有一個淺灰色背景。要使 LiveGrid 正確運行,需要在表中額外創建一行。因此,如果創建一個要顯示 5 個行的 LiveGrid,那麼所創建的 HTML 表需要 6 行。如果沒有額外的行,那麼 LiveGrid 的滾動功能將失常。清單 4 顯示了創建 LiveGrid 使用的 HTML 表所需的代碼。
<div id="movieDiv" style="float:left"> <table id="movie_grid" cellspacing="0" cellpadding="0" width = "400px" style="border:1px solid #ababab" > <tr> <td width="30"> </td> <td width="310"> </td> <td width="60"> </td> </tr> <tr> <td bgcolor="#eeeeee" width="30"> </td> <td bgcolor="#eeeeee" width="310"> </td> <td bgcolor="#eeeeee" width="60"> </td> </tr> <tr> <td width="30"> </td> <td width="310"> </td> <td width="60"> </td> </tr> <tr> <td bgcolor="#eeeeee" width="30"> </td> <td bgcolor="#eeeeee" width="310"> </td> <td bgcolor="#eeeeee" width="60"> </td> </tr> <tr> <td width="30"> </td> <td width="310"> </td> <td width="60"> </td> </tr> <tr> <td bgcolor="#eeeeee" width="30"> </td> <td bgcolor="#eeeeee" width="310"> </td> <td bgcolor="#eeeeee" width="60"> </td> </tr> </table> </div> 設置好表和數據之後,就可以定義用於將清單 4 中的 HTML 表變爲 Rico LiveGrid 的 JavaScript 函數。清單 5
中顯示的函數名爲 |
<script> function loadGrid() { var opts = { prefetchBuffer: true, onscroll : updateLabel }; var liveGrid = new Rico.LiveGrid( 'movie_grid',5, 20, 'MovieData', opts); } </script> |
loadGrid
函數中的第一行指定 LiveGrid 的選項。當把 prefetchBuffer
選項設爲 true 時,就是告訴 Rico 在構造 LiveGrid 時取數據。如果將這個選項設爲 false,那麼 LiveGrid 裝載時沒有任何數據,直到單擊一次滾動條之後才顯示數據。
通過使用 onScroll
選項可以定義一個函數,每當用戶單擊滾動條時,Rico 就調用這個函數。在這個例子中,需要更新顯示文本 "Showing 1 - 5 of 20 Movies" 的 label。爲此,可以定義一個名爲 updateLabel
的 JavaScript 函數,並讓 Rico 在用戶單擊滾動條的時候調用該函數。還可以使用本例中沒有使用的 onscrollidle
選項來定義當滾動暫停或停止時調用的 JavaScript 函數。
另一個有用的選項是 requestParameters
,可以使用該選項將額外的參數發送至處理 Ajax 請求的服務。還可以使用 requestParameters
過濾 LiveGrid 中顯示的數據。例如,如果只想在 LiveGrid 中顯示動作片,那麼可以將 requestParameters
設置爲 genre=action,處理 Ajax 調用的服務將返回那種類型的影片。
loadGrid
函數中的第二行聲明 LiveGrid。構造函數中的第一個參數是被轉換成 LiveGrid 的 HTML 表的 ID。在這個例子中,這個 ID 爲 "movie_grid
"。第二個參數表明要在 LiveGrid 中顯示多少行,在這個例子中是 5 行。第三個參數表明 LiveGrid 中的最大行數,在這個例子中爲 20。第四個參數應該爲負責處理 Ajax 調用的服務器端 script/servlet 的 URL。在這個例子中,我創建了一個名爲 MovieData 的 servlet,用於處理來自 Rico 的 Ajax 請求。
每當裝載 HTML 頁面時,需要調用 loadGrid
函數。清單 6 顯示了這是怎麼完成的。
<body οnlοad="javascript:loadGrid()"> |
最後,定義用於更新 Movie LiveGrid 上的 label 的函數,如清單 7 所示。
<script> function updateLabel( liveGrid, offset ) { $('showingLabel').innerHTML = "Showing " + (offset+1) + " - " + (offset+liveGrid.metaData.getPageSize()) + " of " + liveGrid.metaData.getTotalRows() + " movies"; } </script> |
每當用戶單擊滾動條時,就會調用 updateLabel
函數。它主要組合變量和 Rico 庫來構造出類似 "Showing 1 - 5 of 20 movies" 的字符串。 如果不熟悉 Prototype JavaScript 框架,可以使用 $(DIVNAME)
語法用與 DIVNAME
匹配的 ID 引用頁面上的任何對象。因此,$('showingLabel').innerHTML
相當於 document.getElementById("showingLabel").innerHTML
。在這個例子中,每當用戶單擊滾動條時,便用一個更新的字符串替換 DIV
標記的 innerHTML
值。
Rico 中的大部分代碼編寫工作是在客戶端進行的,但在服務器端也有一些重要的事情要做。也就是說,需要設置服務器端腳本或 servlet 來處理 Ajax 調用。如前所說,我創建了一個例子 servlet,用於處理來自 Rico 的 Ajax 請求。清單 8 顯示爲了使 LiveGrid 小部件正常運行,應該如何編寫來自 servlet 的 XML 響應。
<?xml version="1.0" encoding="ISO-8859-1"?> <ajax-response> <response type="object" id='movie_grid_updater'> <rows update_ui='true' > <tr> <td>1</td> <td>Star Wars</td> <td>1977</td> </tr> <tr> <td>2</td> <td >The Godfather</td> <td>1972</td> </tr> ... </rows> </response> </ajax-response> |
注意,response 標記中 id 屬性的前兩個單詞("movie_grid
")與之前爲 LiveGrid 定義的 HTML 表中的 id 屬性是匹配的。爲了使 Rico 更新 LiveGrid 中的數據,它們應該匹配。在通常情況下,服務器端腳本或 servlet 連接到數據源,並生成以上格式的 XML。Rico 負責從這個 XML 響應中提取數據,並用新數據填充 LiveGrid。注意要將響應的 content-type 設置爲 "text/xml"。如果沒有這樣做,LiveGrid 將不能工作。XML 版本和編碼也必須分別設置爲 "1.0" 和 "ISO-8859-1"。可以如清單 9 所示用 Java™ 代碼設置 content-type。
清單 9. 設置 Ajax 響應的 content-type
response.setHeader("Content-Type", "text/xml"); |
現在,您可能對腳本或 servlet 如何知道何時生成什麼數據感到困惑。在本文的前面,我提到 Rico 框架使用了緩衝技術,當它需要數據時,它就會請求數據。當 Rico 向後端發出一個 Ajax 請求時,它可能會以 URL 中的查詢字符串的形式發送 4 個參數。當提供了這些參數時,後端必須使用這些參數來生成適當的 Ajax 響應。這 4 個參數是:
- offset
- 表明返回的數據集中的第一行數據是什麼。舉個例子,假設 LiveGrid 一開始裝載時 offset 爲 0。Rico 在初始裝載期間取出 150 行數據,並使用緩衝區存儲該數據。在顯示完所有 150 行數據之後,它將 offset 值設爲 151,並向後端發出一個 Ajax 請求。
- page_size
- 表明 Rico 要後端返回的數據的行數。
- sort_col
- 表明將數據返回到 Rico 之前,按哪個列對數據進行排序。
- sort_dir
- 表明按升序還是降序(ACS 或 DECS)對列進行排序。