在上一篇文章中,已經討論了程序的結構和頁面的佈局,並簡單介紹了一些jQuery Mobile的使用技巧。在本篇文章中,筆者將繼續完成咱們web應用的新聞瀏覽器的設計。php
程序的啓動css
咱們如今來研究一下程序的啓動。當程序啓動的時候,展現給用戶的是新聞分類列表的頁面,爲了讓每次這個新聞分類頁面不爲空,咱們須要記下用戶以前選擇了 哪些感興趣的分類。爲了實現這個目的,咱們經過使用jQuery的一個插件DST.js plugin去把用戶每次選擇的新聞分類都保存在HTML5的localStorage中。若是用戶移除了某個分類,則也會在瀏覽器中的本地存儲區域中移 走(注意,要在支持HTML5標準的瀏覽器中才能實現這個功能)。當頁面裝載的時候,咱們能夠在jQuery的$(document).ready()函 數中得到已保存的新聞分類而且逐一處理每一個新聞分類下的最新新聞,代碼以下:html
var COMMA = ','; var COOKIE_NAME = 'news'; // numNewsToRestore保存用戶選擇的新聞分類個數 var numNewsToRestore= 0; var storedNewsArr; ... $(document).ready(function () { showProgress(); var storedNewsTxt = $.DSt.get(COOKIE_NAME); if(storedNewsTxt != null && storedNewsTxt.length > 0){ storedNewsArr = storedNewsTxt.split(COMMA); }else{ storedNewsArr = new Array(); } numNewsToRestore = storedNewsArr.length; restore(); });
在上面的代碼中,當用戶選擇了新聞分類後,會將選擇的新聞以逗號的方式鏈接,存儲在變量storedNewsArr中,好比用戶選擇了「Top Stories」和「Politics」,則在localStorage存儲區域中,會包含字符串「topstories,politics」,接着咱們 調用以下所示的restore()函數:jquery
function restore(){ if(numNewsToRestore > 0){ getNews(storedNewsArr[--numNewsToRestore],restoreNews); }else{ showCategories(); } }
在restore()方法中,若是不存在新聞分類目錄,則咱們只須要顯示一個空的新聞頁。若是存在新聞分類,則調用getNews()方法,並將最新的 一個分類做爲參數傳進去。getNews()方法的另一個參數是restoreNews,接下來看下getNews()和restoreNews()方 法:android
var NEWS_URI = 'bridge.php?fwd=http://rss.news.yahoo.com/rss/'; ... function getNews(varCat,handler){ var varURI = NEWS_URI + varCat; $.ajax({type: GET, dataType: XML, url: varURI, success: handler}); return false; } ... function restoreNews(xml){ populateSingleNews(xml); restore(); }
getNews()方法中提供了向ajax發起請求的地址varURI,這個uri形如以下的形 式:bridge.php?fwd=http://rss.news.yahoo.com/rss/+ varCat,其中varCat就是用戶選擇的新聞目錄,好比bridge.php?fwd=http://rss.news.yahoo.com /rss/topstories。而ajax返回的回調函數爲restoreNews()。在restoreNews()中,又調用了一個自定義的方法 populateSingleNews(),這個方法稍後會解析。而最後又從新調用了restore方法,造成了一個遞歸調用,順序爲:web
restore -> getNews -> restoreNews -> restore -> ...
其中參數numNewsToRestore指的是用戶選擇了多少個新聞分類。在jQuery的ready方法中,首先使用插件DST.js plugin把cookie讀取出來後,造成了字符串數組storedNewsArr,接着調用restore方法,將storedNewsArr中的最 後一個元素(也就是最新用戶選擇的分類)傳入getNews方法中進而得到該分類下的新聞,並經過restoreNews()方法去處理ajax回調返回 的內容,最後又再調用restore() 方法處理storedNewsArr數組中的倒數第2個新聞分類,如此類推。ajax
增長新聞分類數組
如今咱們討論如何增長一個新聞分類,這將在populateSingleNews()中實現。而populateSingleNews()中是根據返回 的XML使用jQuery進行解析,將解析後的結果經過jQuery Mobile的UI展示出來。爲了方便討論,先選取一段Yahoo News返回的RSS進行討論,以下:瀏覽器
<rss> <channel> ... <category>business</category> <description>Business News</description> ... <item> ... <title>Retirement Looms: Time to Get Nervous (BusinessWeek)</title> ... </item> <item> ... <title>European stocks rise as Japan pledges help (AFP)</title> ... </item> ... </channel> </rss>
上面是Business分類下的兩條新聞的RSS XML文件摘錄,其中對XML的解析結果會保存在currentNews變量中。接下來,將分步介紹populateSingleNews方法的實現。服務器
1)得到新聞分類和新聞分類的描述
var CATEGORY = 'category'; var DESCR = 'description'; ... function populateSingleNews(xml){ var tmpTxt = $(xml).find(CATEGORY).first().text(); var desc = $(xml).find(DESCR).first().text(); ... }
首先,咱們調用jQuery的find().first().text()方法去解析xml,分別得到了分類的目錄和描述,以上面的xml爲例子,獲得的結果是tmpTxt='business' 和desc='Business News'.
2) 得到新聞分類的列表
var CAT_ = 'cat_'; var _D = '_d'; var _LI = '_li'; var _A = '_a'; ... function populateSingleNews(xml){ ... var category = CAT_ + tmpTxt; var categoryDel = category + _D; var categoryLi = categoryDel + _LI; var categoryA = category + _A; ... }
上面的代碼,實際上會組合成以下形式的變量:
category='cat_business' categoryDel='cat_business_d' categoryLi='cat_business_d_li' categoryA='cat_business_a'Next
接下來,爲了重用代碼,咱們編寫了以下的代碼段:
var HTML_FRG1 = '<li id="'; var HTML_FRG2 = '"><h3><a id="'; var HTML_FRG3 = '" href="#">'; var HTML_FRG4 = '</a></h3><p id="'; var HTML_FRG5 = '"></p><a href="#" data-transition="slideup" id="'; var HTML_FRG6 = '"/></li>';
最後,將上述的代碼添加到currentNews後,代碼以下:
var currentNewsVar = $('#currentNews'); ... function populateSingleNews(xml){ ... $(HTML_FRG1 + categoryLi + HTML_FRG2 + categoryA + HTML_FRG3 + desc + HTML_FRG4 + category + HTML_FRG5 + categoryDel + HTML_FRG6).prependTo(currentNewsVar); ... }
實際上,以上代碼的效果就會使用jQuery中的prependTo()方法,把以下的代碼加到id="currentNews"的元素以後,即:
<li id="cat_business_d_li"> <h3><a id="cat_business_a" href="#">Business News</a></h3> <p id="cat_business"></p> <a href="#" data-transition="slideup" id="cat_business_d"/> </li>
若是你還不是很清楚的話,下面這個圖,將生動的講解了其對應的結構:
▲圖1 新聞分類列表DOM結構圖
這裏的p標籤,即id="cat_business"部分,是稍後用來作動畫變化時用到的;
觀察這裏的<a id="cat_business_d">標籤,這個標籤是用來當點右邊的刪除按鈕時,產生的刪除事件效果時要用到的Business News;
data-split-icon樣式是使用了jQuery Mobile中默認的刪除按鈕;
The data-split-theme屬性指定使用了什麼風格樣式的刪除按鈕,這裏咱們使用了d樣式的風格刪除按鈕,若是不指定的話,默認使用的是a風格樣式的按鈕。
接下來,咱們將討論
處理刪除按鈕事件 處理當用戶點每一個新聞分類時,跳轉到具體的新聞分類下的新聞列表事件 學習如何設計新聞分類標題出現時的動畫效果 處理刪除按鈕事件
處理刪除按鈕事件的代碼以下:
function populateSingleNews(xml){ ... var newDeleteItem = document.getElementById(categoryDel); $(newDeleteItem).click(function() { $.doTimeout( categoryLi, false ); var newListItem = document.getElementById(categoryLi); $(newListItem).remove(); storeCurrentNews(); }); ... }
還記得categoryLi='cat_business_d_li'麼?咱們調用了$.doTimeout( categoryLi, false )去實現了當刪除新聞分類時,出現的動畫效果。$.doTimeout是來自插件jquery-dotimeout-plugin實現的功能,咱們在稍侯 的動畫部分將會詳細討論。接下來找到了新聞分類的標記newListItem並使用jQuery的remove()方法將其刪除。在刪除新聞分類後,再調 用storeCurrentNews()方法,從新將當前剩下的新聞分類進行保存,這個方法稍後會詳細討論。
查看新聞頁
當用戶點某個新聞分類的標題後,就會跳轉到新聞列表頁,其中會列出所選新聞分類下的新聞,代碼以下:
function populateSingleNews(xml){ ... var newDescItem = document.getElementById(categoryA); $(newDescItem).click(function() { showProgress(); getNews(category.substring(4),populateNewsItems); }); ... }
咱們找到了標籤categoryA,這個值其實就是新聞分類標題的id值,即:
<h3><a id="cat_business_a" href="#">Business News</a></h3>
接着,調用showProgress去顯示等待進度的圖標。
還記得咱們以前的category變量爲'cat_business'麼?這裏咱們用substring(4)方法,取得了實際的分類名,也就是business。
這裏再次調用了getNews方法,但此次回調的函數是populateNewsItems,稍後會詳細介紹。
顯示新聞標題時的動畫效果
populateSingleNews方法中的最後一個部分就是當每一個分類下有最新新聞時,動畫顯示其新聞標題的效果,將其內容顯示在<p id="cat_business">中,代碼以下:
var REFRESH = 'refresh'; ... var ITEM = 'item'; var TITLE = 'title'; ... function populateSingleNews(xml){ ... var ind = 0; var newsArray = new Array(); $(xml).find(ITEM).each(function(){ var txt = $(this).find(TITLE).text(); newsArray[ind++] = txt; }); var newItem = document.getElementById(category); $(newItem).text(newsArray[0]); currentNewsVar.listview(REFRESH); animate(newsArray,$(newItem),categoryLi); }
首先經過find()和each方法將XML中的新聞標題(即RSS XML中的title標籤中的內容)保存到數組newsArray中。
接着將newsArray數組中的第1個元素,也就是最新的一條新聞,經過jQuery的text方法放到<p id="cat_business">標籤中去。
以後調用jQuery Mobile中封裝好的listview的refresh方法,就能夠刷新當前目錄區域內的內容。
最後,調用animate方法,其中傳入的參數是newsArray數組,<p id="cat_business">標籤和當前目錄分類的區域標籤(categoryLi='cat_business_d_li'),下面來說解下如何實現動畫效果。
動畫效果
代碼以下:
var TWO_SECONDS = 2000; ... function animate(pArr,animationTarget,handle){ var len = pArr.length; var currInd = 1; animationTarget.doTimeout(handle,TWO_SECONDS, function(){ this.fadeOut(function(){ currInd = currInd % len; animationTarget.text(pArr[currInd++]); animationTarget.fadeIn(); }); return true; }); }
在顯示動畫的方法中,pArr參數是傳入的新聞列表,animationTarget是最新新聞要顯示的位置區域。而經過使用jquery- dotimeout-plugin這個插件去實現最新新聞的淡入淡出顯示,這個插件的效果有點象Javascript中的setTimeout()方法。 這裏咱們定義了每隔2秒,就顯示新聞列表數組pArr中的內容。
而這個動畫效果會持續運行下去,但持續到何時結束呢?將會知道執 行$.doTimeout(…,false)時才結束。還記得在populateSingleNews方法中,在刪除新聞分類時,有一 行$.doTimeout(categoryLi, false)麼?這裏實際上就是說在刪除新聞分類前,先中止動畫效果的更新。
查看新聞詳細頁的編寫
如今咱們來看下,當用戶點某個新聞分類標題後,將會跳轉到列出該分類下的新聞列表這個功能如何實現,爲方便起見,先以以下的RSS XML爲例子進行說明:
<rss> <channel> ... <category>business</category> <description>Business News</description> ... <item> ... <title>Retirement Looms: Time to Get Nervous (BusinessWeek)</title> ... <description>Let the retirement parties begin: The oldest members of the 1946-64 demographic wave known as the Baby Boom turn 65 this month.</description> </item> ... </channel> </rss>
下面看下populateNewsItems()的編寫:
var EMPTY = ''; var ITEM = 'item'; var DESCR = 'description'; ... var HTML_FRG7 = '<p>'; var HTML_FRG8 = '</p><hr></hr>'; ... var contentNewsVar = $('#contentNews'); ... function populateNewsItems(xml){ var tmpTxt = EMPTY; $(xml).find(ITEM).each(function(){ var txt = $(this).find(DESCR).text(); tmpTxt = tmpTxt + HTML_FRG7 + txt + HTML_FRG8; }); contentNewsVar.html(tmpTxt); showNews(); }
咱們經過jQuery的find()和each()解析XML,對於每一個item元素,取出其新聞的詳細內容即description子元素內容放到變量txt中去,最後用<p></p>將其包裹起來,並最後加上一個水平線做爲分隔。
最後經過jQuery的html()方法將<div id="contentNews">的值設置爲tmpTxt,記得<div id="contentNews">就是新聞內容的區域。
增長用戶本身喜愛的新聞分類
當在增長新聞分類頁中,點‘Get Category’按鈕後,觸發buttonGetCategoryVar.click()事件,代碼以下:
var buttonGetCategoryVar = $('#buttonGetCategory'); var categoryVar = $('#category'); var EMPTY = ''; ... buttonGetCategoryVar.click(function() { if(categoryVar.val() != EMPTY){ showProgress(); return getNews(categoryVar.val(),addNews); }else{ showCategories(); return false; } }); ... function addNews(xml){ populateSingleNews(xml); storeCurrentNews(); showCategories(); }
在點‘Get Category’ 按鈕後,首先判斷下拉列表框中用戶是否選擇了新聞分類,若是選擇了新聞分類則調用getNews方法,getNews()方法咱們已經討論過,實際上就是 這裏把選擇的新聞分類名稱經過ajax調用發送到服務端,得到服務端返回的XML內容。
在getNews方法的回調方法中,調用的是 populateSingleNews(xml);緣由是在增長完新聞分類後,跳轉到的頁面中,是顯示剛新增的一個分類以及其最新的一條新聞,以下圖,再 調用storeCurrentNews(),把用戶增長的這個新聞分類保存到HTML5中的localStorage中。
▲圖2 上面這個圖中,用戶選擇了兩個新聞分類U.S.News和Economy News。
保存用戶選擇的新聞分類
如今咱們回過頭來看如何使用HTML5的localStorage特性去保存用戶選擇的新聞分類。
代碼以下:
var COOKIE_NAME = 'news'; var COMMA = ','; var EMPTY = ''; var LI = 'li'; var PAR = 'p'; var ID = 'id'; ... var currentNewsVar = $('#currentNews'); ... function storeCurrentNews(){ $.DSt.set(COOKIE_NAME, EMPTY); var tmp = EMPTY; currentNewsVar.find(LI).each(function(){ tmp = tmp + COMMA + $(this).find(PAR).attr(ID).substring(4); }); $.DSt.set(COOKIE_NAME, tmp.substring(1)); }
在storeCurrentNews方法中,首先調用DST.js plugin插件清除掉原先保存的cookie。
接着, 使用jQuery的find和each方法,去得到圖2得到新聞分類列表中的每一個分類的名稱,這裏其實是得到<p id='cat_business'>中的cat_business部分,而後再用substring方法得到其實際名稱,這裏即business爲其分類名稱。
最後使用DST.js plugin中的set方法,把用戶選擇的新聞分類列表都保存在cookie中。
其餘事件代碼講解
新聞詳細頁返回主頁的事件代碼
在第一部分中,曾經提到在新聞詳細內容頁的頭部和底部都有按鈕返回到主頁,其代碼以下,很是簡單,只是調用showCategories代碼,具體見下載附件。
var buttonHdrShowCategoriesVar = $('#buttonHdrShowCategories'); var buttonFtrShowCategoriesVar = $('#buttonFtrShowCategories'); buttonHdrShowCategoriesVar.click(function() { showCategories(); return false; }); buttonFtrShowCategoriesVar.click(function() { showCategories(); return false; });
關於AJAX請求
最後咱們來討論ajax請求部分,在這裏,咱們是經過使用bridge.php做爲中轉,對Yahoo的新聞發起ajax請求,從新複習下getNews的代碼:
var NEWS_URI = 'bridge.php?fwd=http://rss.news.yahoo.com/rss/'; function getNews(varCat,handler){ var varURI = NEWS_URI + varCat; $.ajax({type: GET, dataType: XML, url: varURI, success: handler}); return false; }
在上面的代碼中,index.html和bridge.php都運行在同一服務器環境中,實際向yahoo發出的請求會是這個樣子:
bridge.php?fwd=http://rss.news.yahoo.com/rss/business,而bridge.php會經過php 的cUrl方法向Yahoo發出請求,將得到的xml信息寫在文件tmpFile.txt中,具體代碼以下,關於php的cUrl方法請參考PHP手冊, 這裏再也不詳細介紹。
<?php header('Content-Type: application/xml'); $tmpFile = 'tmpFile.txt'; $val = $_GET["fwd"]; $curlHandle = curl_init($val); $filePointer = fopen($tmpFile, "w"); curl_setopt($curlHandle, CURLOPT_FILE, $filePointer); curl_exec($curlHandle); curl_close($curlHandle); fclose($filePointer); $linesArr = file($tmpFile); foreach($linesArr as $eachLine){ echo($eachLine); } ?>
Web項目的結構
最後,咱們簡單介紹下web項目的結構,詳細的請參考附件。
項目根目錄下包含 index.html and bridge.php.
css-js下包含了全部的css和Javascript文件,以下
jquery-1.4.4.min.js, jquery.mobile-1.0a2.min.js,jquery.mobile-1.0a2.min.css 這些都是jQuery Mobile的文件
jquery.ba-dotimeout.js 爲 jquery-dotimeout-plugin 庫文件.
jquery.dst.js 爲 DST.js plugin 庫文件.
news\img\wait.gif 爲等待圖標,最後,記得引用這些Javascript代碼庫,以下:
<link rel="stylesheet" href="css-js/jquery.mobile-1.0a2.min.css" /> <script src="css-js/jquery-1.4.4.min.js"></script> <script src="css-js/jquery.mobile-1.0a2.min.js"></script> <script src="css-js/jquery.ba-dotimeout.js"></script> <script src="css-js/jquery.dst.js"></script>
小結
在本文中,介紹瞭如何使用jQuery Mobile去實現一個web版本的新聞閱讀器,其中講解了jQuery Mobile及jquery-dotimeout插件,jquery.dst插件的使用,在下一篇教程中,將詳細講解如何將已經實現的web應用遷移到 android上去。