使用HTML5开发离线应用 - cache manifest
HTML5 是目前正在討論的新一代 HTML 標(biāo)準(zhǔn),它代表了現(xiàn)在 Web 領(lǐng)域的最新發(fā)展方向。在 HTML5
標(biāo)準(zhǔn)中,加入了新的多樣的內(nèi)容描述標(biāo)簽,直接支持表單驗(yàn)證、視頻音頻標(biāo)簽、網(wǎng)頁(yè)元素的拖拽、離線存儲(chǔ)和工作線程等功能。其中一個(gè)新特性就是對(duì)離線應(yīng)用開(kāi)發(fā)的支持。
在開(kāi)發(fā)支持離線的 Web 應(yīng)用程序時(shí),開(kāi)發(fā)者通常需要使用以下三個(gè)方面的功能:
中,通過(guò) cache manifest 文件指明需要緩存的資源,并支持自動(dòng)和手動(dòng)兩種緩存更新方式。
中,提供了兩種檢測(cè)當(dāng)前網(wǎng)絡(luò)是否在線的方式。
SQL Database 兩種存儲(chǔ)機(jī)制。前者提供了易用的 key/value 對(duì)存儲(chǔ)方式,而后者提供了基本的關(guān)系數(shù)據(jù)庫(kù)存儲(chǔ)功能。
盡管 HTML5 還處于草稿狀態(tài),但是各大主流瀏覽器都已經(jīng)實(shí)現(xiàn)了其中的很多功能。Chrome、Firefox、Safari 和 Opera 的最新版本都對(duì)
HTML5 離線功能提供了完整的支持。IE8 也支持了其中的在線狀態(tài)檢測(cè)和 DOM Storage 功能。下面將具體介紹 HTML5
離線功能中的離線資源緩存、在線狀態(tài)檢測(cè)、DOM Storage 和 Web SQL Database,最后通過(guò)一個(gè)簡(jiǎn)單的 Web 程序說(shuō)明使用 HTML5
開(kāi)發(fā)離線應(yīng)用的方法。
回頁(yè)首
離線資源緩存
為了能夠讓用戶在離線狀態(tài)下繼續(xù)訪問(wèn) Web 應(yīng)用,開(kāi)發(fā)者需要提供一個(gè) cache manifest
文件。這個(gè)文件中列出了所有需要在離線狀態(tài)下使用的資源,瀏覽器會(huì)把這些資源緩存到本地。本節(jié)先通過(guò)一個(gè)例子展示 cache manifest
文件的用途,然后詳細(xì)描述其書(shū)寫(xiě)方法,最后說(shuō)明緩存的更新方式。
cache manifest 示例
我們通過(guò) W3C 提供的示例來(lái)說(shuō)明。Clock Web
應(yīng)用由三個(gè)文件“clock.html”、“clock.css”和“clock.js”組成。
清單 1.
Clock 應(yīng)用代碼
| <!-- clock.html --> <!DOCTYPE HTML> <html> <head> <title>Clock</title> <script src="clock.js"></script> <link rel="stylesheet" href="clock.css"> </head> <body> <p>The time is: <output id="clock"></output></p> </body> </html> /* clock.css */ output { font: 2em sans-serif; } /* clock.js */ setTimeout(function () { document.getElementById('clock').value = new Date(); }, 1000); |
當(dāng)用戶在離線狀態(tài)下訪問(wèn)“clock.html”時(shí),頁(yè)面將無(wú)法展現(xiàn)。為了支持離線訪問(wèn),開(kāi)發(fā)者必須添加 cache manifest
文件,指明需要緩存的資源。這個(gè)例子中的 cache manifest 文件為“clock.manifest”,它聲明了 3
個(gè)需要緩存的資源文件“clock.html”、“clock.css”和“clock.js”。
清單 2.
clock.manifest 代碼
| CACHE MANIFEST clock.html clock.css clock.js |
添加了 cache manifest 文件后,還需要修改“clock.html”,把 <html> 標(biāo)簽的 manifest
屬性設(shè)置為“clock.manifest”。修改后的“clock.html”代碼如下。
清單 3. 設(shè)置
manifest 后的 clock.html 代碼
| <!-- clock.html --> <!DOCTYPE HTML> <html manifest="clock.manifest"> <head> <title>Clock</title> <script src="clock.js"></script> <link rel="stylesheet" href="clock.css"> </head> <body> <p>The time is: <output id="clock"></output></p> </body> </html> |
修改后,當(dāng)用戶在線訪問(wèn)“clock.html”時(shí),瀏覽器會(huì)緩存“clock.html”、“clock.css”和“clock.js”文件;而當(dāng)用戶離線訪問(wèn)時(shí),這個(gè)
Web 應(yīng)用也可以正常使用了。
cache manifest 格式
下面說(shuō)明書(shū)寫(xiě) cache manifest 文件需要遵循的格式。
不可訪問(wèn)時(shí),瀏覽器將嘗試使用第二個(gè) URI。
清單 4 的代碼中給出了 cache manifest 中各類標(biāo)識(shí)符的使用示例。
清單 4.
cache manifest 示例代碼
| CACHE MANIFEST # 上一行是必須書(shū)寫(xiě)的。images/sound-icon.png images/background.png NETWORK: comm.cgi |
# 下面是另一些需要緩存的資源,在這個(gè)示例中只有一個(gè) css 文件。
| CACHE: style/default.css FALLBACK: /files/projects /projects |
更新緩存
應(yīng)用程序可以等待瀏覽器自動(dòng)更新緩存,也可以使用 Javascript 接口手動(dòng)觸發(fā)更新。
瀏覽器除了在第一次訪問(wèn) Web 應(yīng)用時(shí)緩存資源外,只會(huì)在 cache manifest 文件本身發(fā)生變化時(shí)更新緩存。而 cache manifest
中的資源文件發(fā)生變化并不會(huì)觸發(fā)更新。
開(kāi)發(fā)者也可以使用 window.applicationCache 的接口更新緩存。方法是檢測(cè) window.applicationCache.status
的值,如果是 UPDATEREADY,那么可以調(diào)用 window.applicationCache.update()
更新緩存。示范代碼如下。
清單 5 手動(dòng)更新緩存
| if (window.applicationCache.status == window.applicationCache.UPDATEREADY) {window.applicationCache.update(); } |
?
回頁(yè)首
在線狀態(tài)檢測(cè)
如果 Web 應(yīng)用程序僅僅是一些靜態(tài)頁(yè)面的組合,那么通過(guò) cache manifest
緩存資源文件以后,就可以支持離線訪問(wèn)了。但是隨著互聯(lián)網(wǎng)的發(fā)展,特別是 Web2.0 概念流行以來(lái),用戶的提交的數(shù)據(jù)漸漸成為互聯(lián)網(wǎng)的主流。那么在開(kāi)發(fā)支持離線的
Web
應(yīng)用時(shí),就不能僅僅滿足于靜態(tài)頁(yè)面的展現(xiàn),還必需考慮如何讓用戶在離線狀態(tài)下也可以操作數(shù)據(jù)。離線狀態(tài)時(shí),把數(shù)據(jù)存儲(chǔ)在本地;在線以后,再把數(shù)據(jù)同步到服務(wù)器上。為了做到這一點(diǎn),開(kāi)發(fā)者首先必須知道瀏覽器是否在線。HTML5
提供了兩種檢測(cè)是否在線的方式:navigator.online 和 online/offline 事件。
navigator.onLine 屬性表示當(dāng)前是否在線。如果為 true, 表示在線;如果為 false,
表示離線。當(dāng)網(wǎng)絡(luò)狀態(tài)發(fā)生變化時(shí),navigator.onLine 的值也隨之變化。開(kāi)發(fā)者可以通過(guò)讀取它的值獲取網(wǎng)絡(luò)狀態(tài)。
當(dāng)開(kāi)發(fā)離線應(yīng)用時(shí),通過(guò) navigator.onLine 獲取網(wǎng)絡(luò)狀態(tài)通常是不夠的。開(kāi)發(fā)者還需要在網(wǎng)絡(luò)狀態(tài)發(fā)生變化時(shí)立刻得到通知,因此 HTML5
還提供了 online/offline 事件。當(dāng)在線 / 離線狀態(tài)切換時(shí),online/offline 事件將觸發(fā)在 body 元素上,并且沿著
document.body、document 和 window 的順序冒泡。因此,開(kāi)發(fā)者可以通過(guò)監(jiān)聽(tīng)它們的 online/offline
事件來(lái)獲悉網(wǎng)絡(luò)狀態(tài)。
回頁(yè)首
DOM Storage
在開(kāi)發(fā)支持離線功能的 Web 應(yīng)用時(shí),開(kāi)發(fā)者需要在本地存儲(chǔ)數(shù)據(jù)。當(dāng)前瀏覽器支持的 cookie 雖然也可以用來(lái)存儲(chǔ)數(shù)據(jù),但是 cookie
長(zhǎng)度非常小(通常幾 k),而且功能有限。因此,HTML5 中新引入了 DOM Storage 機(jī)制,用于存儲(chǔ) key/value
對(duì),它的設(shè)計(jì)目標(biāo)是提供大規(guī)模、安全且易用的存儲(chǔ)功能。
DOM Storage 分類
DOM Storage 分為兩類:sessionStorage 和 localStorage。除了以下區(qū)別外,這兩類存儲(chǔ)對(duì)象的功能是完全一致的。
localStorage 的數(shù)據(jù)。
DOM Storage 接口
每一個(gè) Storage 對(duì)象都可以存儲(chǔ)一系列 key/value 對(duì),Storage 接口定義為:
| interface Storage { readonly attribute unsigned long length; getter DOMString key(in unsigned long index); getter any getItem(in DOMString key); setter creator void setItem(in DOMString key, in any data); deleter void removeItem(in DOMString key); void clear(); }; |
其中最常用的接口是 getItem 和 setItem。getItem 用于獲取指定 key 的 value,而 setItem 用于設(shè)置指定 key 的
value。
DOM Storage 示例
這里給出一個(gè)使用了 sessionStorage 的例子,localStorage 的用法與它相同。首先使用 SetItem
添加了一個(gè)名為“userName”的項(xiàng),它的值是“developerworks”。然后,調(diào)用 getItem
得到“userName”的值,并且彈出提示框顯示它。最后,調(diào)用 removeItem 刪除“userName”。
清單 6 DOM Storage 示例代碼
| <!DOCTYPE HTML> <html> <body> <script> // 在 sessionStorage 中定義'userName'變量sessionStorage.setItem('userName', 'developerworks'); // 訪問(wèn)'userName'變量alert("Your user is: " + sessionStorage.getItem('userName')); // 最后刪除'userName'sessionStorage.removeItem('userName'); </script> </body> </html> |
回頁(yè)首
Web SQL Database
除了 DOM Storage 以外,HTML5 中還有另外一種數(shù)據(jù)存儲(chǔ)方式 Web SQL
Database。它提供了基本的關(guān)系數(shù)據(jù)庫(kù)功能,支持頁(yè)面上的復(fù)雜的、交互式的數(shù)據(jù)存儲(chǔ)。它既可以用來(lái)存儲(chǔ)用戶產(chǎn)生的數(shù)據(jù),也可以作為從服務(wù)器獲取數(shù)據(jù)的本地高速緩存。例如可以把電子郵件、日程等數(shù)據(jù)存儲(chǔ)到數(shù)據(jù)庫(kù)中。Web
SQL Database 支持?jǐn)?shù)據(jù)庫(kù)事務(wù)的概念,從而保證了即使多個(gè)瀏覽器窗口操作同一數(shù)據(jù),也不會(huì)產(chǎn)生沖突。
Web SQL Database 基本用法
使用數(shù)據(jù)庫(kù)的第一步是創(chuàng)建并打開(kāi)數(shù)據(jù)庫(kù),API 是 openDatabase。當(dāng)數(shù)據(jù)庫(kù)已經(jīng)存在時(shí),openDatabase
僅僅打開(kāi)數(shù)據(jù)庫(kù);如果這個(gè)數(shù)據(jù)庫(kù)不存在,那么就創(chuàng)建一個(gè)空數(shù)據(jù)庫(kù)并且打開(kāi)它。openDatabase 的定義是:
| Database openDatabase(in DOMString name, in DOMString version, in DOMString displayName, in unsigned long estimatedSize, in optional DatabaseCallback creationCallback); |
name:數(shù)據(jù)庫(kù)名。
version:數(shù)據(jù)庫(kù)版本。
displayName:顯示名稱。
estimatedSize:數(shù)據(jù)庫(kù)預(yù)估長(zhǎng)度(以字節(jié)為單位)。
creationCallback:回調(diào)函數(shù)。
在打開(kāi)數(shù)據(jù)庫(kù)以后,就可以使用事務(wù) API
transaction。每一個(gè)事務(wù)作為操作數(shù)據(jù)庫(kù)的原子操作,不會(huì)被打斷,從而避免了數(shù)據(jù)沖突。transaction 的定義是:
| void transaction(in SQLTransactionCallback callback, in optional SQLTransactionErrorCallback errorCallback, in optional SQLVoidCallback successCallback); |
callback:事務(wù)回調(diào)函數(shù),其中可以執(zhí)行 SQL 語(yǔ)句。
errorCallback:出錯(cuò)回調(diào)函數(shù)。
successCallback:執(zhí)行成功回調(diào)函數(shù)。
在事務(wù)的回調(diào)函數(shù) callback 中,可以執(zhí)行 SQL 語(yǔ)句,API 是 executeSQL。executeSQL 的定義是:
| void executeSql(in DOMString sqlStatement, in optional ObjectArray arguments, in optional SQLStatementCallback callback, in optional SQLStatementErrorCallback errorCallback); |
sqlStatement:SQL 語(yǔ)句。
arguments:SQL 語(yǔ)句需要的參數(shù)。
callback:回調(diào)函數(shù)。
errorCallback:出錯(cuò)回調(diào)函數(shù)。
Web SQL Database 示例
下面通過(guò)一個(gè)例子說(shuō)明 Web SQL Database 的基本用法。它首先調(diào)用 openDatabase 創(chuàng)建了名為“fooDB”的數(shù)據(jù)庫(kù)。然后使用
transaction 執(zhí)行兩條 SQL 語(yǔ)句。第一條 SQL 語(yǔ)句創(chuàng)建了名為“foo”的表,第二條 SQL 語(yǔ)句向表中插入一條記錄。
清單 7 Web SQL Database 示例代碼
| var db = openDatabase('fooDB', '1.0', 'fooDB', 2 * 1024); db.transaction(function (tx) { tx.executeSql('CREATE TABLE IF NOT EXISTS foo (id unique, text)'); tx.executeSql('INSERT INTO foo (id, text) VALUES (1, "foobar")'); }); |
回頁(yè)首
離線應(yīng)用示例
最后,通過(guò)一個(gè)例子來(lái)說(shuō)明使用 HTML5 開(kāi)發(fā)離線應(yīng)用的基本方法。這個(gè)例子會(huì)用到前面提到的離線資源緩存、在線狀態(tài)檢測(cè)和 DOM Storage
等功能。假設(shè)我們開(kāi)發(fā)一個(gè)便簽管理的 Web
應(yīng)用程序,用戶可以在其中添加和刪除便簽。它支持離線功能,允許用戶在離線狀態(tài)下添加、刪除便簽,并且當(dāng)在線以后能夠同步到服務(wù)器上。
這個(gè)程序的界面很簡(jiǎn)單,如圖 1 所示。用戶點(diǎn)擊“New Note”按鈕可以在彈出框中創(chuàng)建新的便簽,雙擊某便簽就表示刪除它。
圖 1. 應(yīng)用程序頁(yè)面
這個(gè)頁(yè)面的源文件是 index.html,它的代碼如清單 8 所示。
清單 8 頁(yè)面
HTML 代碼
| <html manifest="notes.manifest"> <head> <script type="text/javascript" src="server.js"></script> <script type="text/javascript" src="data.js"></script> <script type="text/javascript" src="UI.js"></script> <title>Note List</title> </head> <body onload = "SyncWithServer()"> <input type="button" value="New Note" οnclick="newNote()"> <ul id="list"></ul> </body> </html> |
在 body 中聲明了一個(gè)按鈕和一個(gè)無(wú)序列表。當(dāng)按下“New Note”按鈕時(shí),newNote
函數(shù)將被調(diào)用,它用來(lái)添加一條新的便簽。而無(wú)序列表初始為空,它是用來(lái)顯示便簽的列表。
定義 cache manifest
文件,聲明需要緩存的資源。在這個(gè)例子中,需要緩存“index.html”、“server.js”、“data.js”和“UI.js”等 4
個(gè)文件。除了前面列出的“index.html”外,“server.js”、“data.js”和“UI.js”分別包含服務(wù)器相關(guān)、數(shù)據(jù)存儲(chǔ)和用戶界面代碼。cache
manifest 文件定義如下。
清單 9 cache manifest
文件
| CACHE MANIFEST index.html server.js data.js UI.js |
?
用戶界面代碼定義在 UI.js 中。
清單 10 用戶界面代碼
UI.js
| function newNote() { var title = window.prompt("New Note:"); if (title) { add(title); } } function add(title) { // 在界面中添加addUIItem(title); // 在數(shù)據(jù)中添加addDataItem(title); } function remove(title) { // 從界面中刪除removeUIItem(title); // 從數(shù)據(jù)中刪除removeDataItem(title); } function addUIItem(title) { var item = document.createElement("li"); item.setAttribute("ondblclick", "remove('"+title+"')"); item.innerHTML=title; var list = document.getElementById("list"); list.appendChild(item); } function removeUIItem(title) { var list = document.getElementById("list"); for (var i = 0; i < list.children.length; i++) { if(list.children[i].innerHTML == title) { list.removeChild(list.children[i]); } } } |
UI.js 中的代碼包含添加便簽和刪除便簽的界面操作。
remove,使得雙擊操作可以刪除便簽。
- 刪除便簽
將在后面列出。
數(shù)據(jù)存儲(chǔ)代碼
數(shù)據(jù)存儲(chǔ)代碼定義在 data.js 中。
清單 11 數(shù)據(jù)存儲(chǔ)代碼
data.js
| var storage = window['localStorage']; function addDataItem(title) { if (navigator.onLine) // 在線狀態(tài){ addServerItem(title); } else // 離線狀態(tài){ var str = storage.getItem("toAdd"); if(str == null) { str = title; } else { str = str + "," + title; } storage.setItem("toAdd", str); } } function removeDataItem(title) { if (navigator.onLine) // 在線狀態(tài){ removeServerItem(title); } else // 離線狀態(tài){ var str = storage.getItem("toRemove"); if(str == null) { str = title; } else { str = str + "," + title; } storage.setItem("toRemove", str); } } function SyncWithServer() { // 如果當(dāng)前是離線狀態(tài),不需要做任何處理if (navigator.onLine == false)return; var i = 0; // 和服務(wù)器同步添加操作var str = storage.getItem("toAdd"); if(str != null) { var addItems = str.split(","); for(i = 0; i<addItems.length; i++) { addDataItem(addItems[i]); } storage.removeItem("toAdd"); } // 和服務(wù)器同步刪除操作str = storage.getItem("toRemove"); if(str != null) { var removeItems = str.split(","); for(i = 0; i<removeItems.length; i++) { removeDataItem(removeItems[i]); } storage.removeItem("toRemove"); } // 刪除界面中的所有便簽 var list = document.getElementById("list"); while(list.lastChild != list.firstElementChild) list.removeChild(list.lastChild); if(list.firstElementChild) list.removeChild(list.firstElementChild); // 從服務(wù)器獲取全部便簽,并顯示在界面中var allItems = getServerItems(); if(allItems != "") { var items = allItems.split(","); for(i = 0; i<items.length; i++) { addUIItem(items[i]); } } } |
window.addEventListener("online", SyncWithServer,false);
data.js 中的代碼包含添加便簽、刪除便簽和與服務(wù)器同步等數(shù)據(jù)操作。其中用到了 navigator.onLine 屬性、online 事件、DOM
Storage 等 HTML5 新功能。
- 刪除便簽:removeDataItem
- 數(shù)據(jù)同步:SyncWithServer
在 data.js 的最后一行,注冊(cè)了 window 的 online 事件處理函數(shù) SyncWithServer。當(dāng) online
事件發(fā)生時(shí),SyncWithServer 將被調(diào)用。其功能如下。
服務(wù)器相關(guān)代碼
服務(wù)器相關(guān)代碼定義在 server.js 中。
清單 12 服務(wù)器相關(guān)代碼
server.js
| function addServerItem(title) { // 在服務(wù)器中添加一項(xiàng)} function removeServerItem(title) { // 在服務(wù)器中刪除一項(xiàng)} function getServerItems() { // 返回服務(wù)器中存儲(chǔ)的便簽列表} |
由于這部分代碼與服務(wù)器有關(guān),這里只說(shuō)明各個(gè)函數(shù)的功能,具體實(shí)現(xiàn)可以根據(jù)不同服務(wù)器編寫(xiě)代碼。
在服務(wù)器中刪除一項(xiàng):removeServerItem
返回服務(wù)器中存儲(chǔ)的便簽列表:getServerItems
轉(zhuǎn)載于:https://www.cnblogs.com/cxd4321/p/3257372.html
總結(jié)
以上是生活随笔為你收集整理的使用HTML5开发离线应用 - cache manifest的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 玩网游的素质怎么都这么差?律师:辱骂账号
- 下一篇: ImageLightbox.js – 响