DIV CSS 佈局教程網

 DIV+CSS佈局教程網 >> 網頁腳本 >> HTML基礎知識 >> HTML5詳解 >> 使用 HTML5 開發離線應用
使用 HTML5 開發離線應用
編輯:HTML5詳解     

Html5 是目前正在討論的新一代 HTML 標准,它代表了現在 Web 領域的最新發展方向。在 Html5 標准中,加入了新的多樣的內容描述標簽,直接支持表單驗證、視頻音頻標簽、網頁元素的拖拽、離線存儲和工作線程等功能。其中一個新特性就是對離線應用開發 的支持。

在開發支持離線的 Web 應用程序時,開發者通常需要使用以下三個方面的功能:

  1. 離線資源緩存:需要一種方式來指明應用程序離線工作時所需的資源文件。這樣,浏覽器才能在在線狀態時,把這些文件緩存到本地。此後,當用戶離線訪問應用程 序時,這些資源文件會自動加載,從而讓用戶正常使用。Html5 中,通過 cache manifest 文件指明需要緩存的資源,並支持自動和手動兩種緩存更新方式。
  2. 在線狀態檢測:開發者需要知道浏覽器是否在線,這樣才能夠針對在線或離線的狀態,做出對應的處理。在 Html5 中,提供了兩種檢測當前網絡是否在線的方式。
  3. 本地數據存儲:離線時,需要能夠把數據存儲到本地,以便在線時同步到服務器上。為了滿足不同的存儲需求,Html5 提供了 DOM Storage 和 Web SQL Database 兩種存儲機制。前者提供了易用的 key/value 對存儲方式,而後者提供了基本的關系數據庫存儲功能。

盡管 HTML5 還處於草稿狀態,但是各大主流浏覽器都已經實現了其中的很多功能。Chrome、Firefox、Safari 和 Opera 的最新版本都對 HTML5 離線功能提供了完整的支持。IE8 也支持了其中的在線狀態檢測和 DOM Storage 功能。下面將具體介紹 Html5 離線功能中的離線資源緩存、在線狀態檢測、DOM Storage 和 Web SQL Database,最後通過一個簡單的 Web 程序說明使用 Html5 開發離線應用的方法。

回頁首

離線資源緩存

為了能夠讓用戶在離線狀態下繼續訪問 Web 應用,開發者需要提供一個 cache manifest 文件。這個文件中列出了所有需要在離線狀態下使用的資源,浏覽器會把這些資源緩存到本地。本節先通過一個例子展示 cache manifest 文件的用途,然後詳細描述其書寫方法,最後說明緩存的更新方式。

cache manifest 示例

我們通過 W3C 提供的示例來說明。Clock Web 應用由三個文件“clock.Html”、“clock.CSS”和“clock.JS”組成。


清單 1. Clock 應用代碼
				   <!-- 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);  

當用戶在離線狀態下訪問“clock.html”時,頁面將無法展現。為了支持離線訪問,開發者必須添加 cache manifest 文件,指明需要緩存的資源。這個例子中的 cache manifest 文件為“clock.manifest”,它聲明了 3 個需要緩存的資源文件“clock.Html”、“clock.CSS”和“clock.JS”。


清單 2. clock.manifest 代碼
				   CACHE MANIFEST   clock.Html   clock.CSS   clock.JS  

添加了 cache manifest 文件後,還需要修改“clock.html”,把 <html> 標簽的 manifest 屬性設置為“clock.manifest”。修改後的“clock.Html”代碼如下。


清單 3. 設置 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>  

修改後,當用戶在線訪問“clock.html”時,浏覽器會緩存“clock.Html”、“clock.CSS”和“clock.JS”文件;而當用戶離線訪問時,這個 Web 應用也可以正常使用了。

cache manifest 格式

下面說明書寫 cache manifest 文件需要遵循的格式。

  1. 首行必須是 CACHE MANIFEST。
  2. 其後,每一行列出一個需要緩存的資源文件名。
  3. 可根據需要列出在線訪問的白名單。白名單中的所有資源不會被緩存,在使用時將直接在線訪問。聲明白名單使用 NETWORK:標識符。
  4. 如果在白名單後還要補充需要緩存的資源,可以使用 CACHE:標識符。
  5. 如果要聲明某 URI 不能訪問時的替補 URI,可以使用 FALLBACK:標識符。其後的每一行包含兩個 URI,當第一個 URI 不可訪問時,浏覽器將嘗試使用第二個 URI。
  6. 注釋要另起一行,以 # 號開頭。

清單 4 的代碼中給出了 cache manifest 中各類標識符的使用示例。


清單 4. cache manifest 示例代碼
				   CACHE MANIFEST   # 上一行是必須書寫的。   images/sound-icon.png   images/background.png    NETWORK:   comm.CGI  

# 下面是另一些需要緩存的資源,在這個示例中只有一個 CSS 文件。

 CACHE:   style/default.CSS    FALLBACK:   /files/projects /projects  

更新緩存

應用程序可以等待浏覽器自動更新緩存,也可以使用 Javascript 接口手動觸發更新。

  1. 自動更新

    浏覽器除了在第一次訪問 Web 應用時緩存資源外,只會在 cache manifest 文件本身發生變化時更新緩存。而 cache manifest 中的資源文件發生變化並不會觸發更新。

  2. 手動更新

    開發者也可以使用 window.applicationCache 的接口更新緩存。方法是檢測 window.applicationCache.status 的值,如果是 UPDATEREADY,那麼可以調用 window.applicationCache.update() 更新緩存。示范代碼如下。



    清單 5 手動更新緩存
    				   if (window.applicationCache.status == window.applicationCache.UPDATEREADY)  {  window.applicationCache.update();  } 

回頁首

在線狀態檢測

如果 Web 應用程序僅僅是一些靜態頁面的組合,那麼通過 cache manifest 緩存資源文件以後,就可以支持離線訪問了。但是隨著互聯網的發展,特別是 Web2.0 概念流行以來,用戶的提交的數據漸漸成為互聯網的主流。那麼在開發支持離線的 Web 應用時,就不能僅僅滿足於靜態頁面的展現,還必需考慮如何讓用戶在離線狀態下也可以操作數據。離線狀態時,把數據存儲在本地;在線以後,再把數據同步到服 務器上。為了做到這一點,開發者首先必須知道浏覽器是否在線。Html5 提供了兩種檢測是否在線的方式:navigator.online 和 online/offline 事件。

  1. navigator.onLine

    navigator.onLine 屬性表示當前是否在線。如果為 true, 表示在線;如果為 false, 表示離線。當網絡狀態發生變化時,navigator.onLine 的值也隨之變化。開發者可以通過讀取它的值獲取網絡狀態。

  2. online/offline 事件

    當開發離線應用時,通過 navigator.onLine 獲取網絡狀態通常是不夠的。開發者還需要在網絡狀態發生變化時立刻得到通知,因此 Html5 還提供了 online/offline 事件。當在線 / 離線狀態切換時,online/offline 事件將觸發在 body 元素上,並且沿著 document.body、document 和 window 的順序冒泡。因此,開發者可以通過監聽它們的 online/offline 事件來獲悉網絡狀態。

回頁首

DOM Storage

在開發支持離線功能的 Web 應用時,開發者需要在本地存儲數據。當前浏覽器支持的 cookIE 雖然也可以用來存儲數據,但是 cookIE 長度非常小(通常幾 k),而且功能有限。因此,Html5 中新引入了 DOM Storage 機制,用於存儲 key/value 對,它的設計目標是提供大規模、安全且易用的存儲功能。

DOM Storage 分類

DOM Storage 分為兩類:sessionStorage 和 localStorage。除了以下區別外,這兩類存儲對象的功能是完全一致的。

  1. sessionStorage 用於存儲與當前浏覽器窗口關聯的數據。窗口關閉後,sessionStorage 中存儲的數據將無法使用。
  2. localStorage 用於長期存儲數據。窗口關閉後,localStorage 中的數據仍然可以被訪問。所有浏覽器窗口可以共享 localStorage 的數據。

DOM Storage 接口

每一個 Storage 對象都可以存儲一系列 key/value 對,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 用於設置指定 key 的 value。

DOM Storage 示例

這裡給出一個使用了 sessionStorage 的例子,localStorage 的用法與它相同。首先使用 SetItem 添加了一個名為“userName”的項,它的值是“developerworks”。然後,調用 getItem 得到“userName”的值,並且彈出提示框顯示它。最後,調用 removeItem 刪除“userName”。


清單 6 DOM Storage 示例代碼
				   <!DOCTYPE HTML>   <html>   <body>   <script>   // 在 sessionStorage 中定義'userName'變量  sessionStorage.setItem('userName', 'developerworks');         // 訪問'userName'變量  alert("Your user is: " + sessionStorage.getItem('userName'));   // 最後刪除'userName'  sessionStorage.removeItem('userName');                         </script>   </body>   </Html>  

回頁首

Web SQL Database

除了 DOM Storage 以外,Html5 中還有另外一種數據存儲方式 Web SQL Database。它提供了基本的關系數據庫功能,支持頁面上的復雜的、交互式的數據存儲。它既可以用來存儲用戶產生的數據,也可以作為從服務器獲取數據 的本地高速緩存。例如可以把電子郵件、日程等數據存儲到數據庫中。Web SQL Database 支持數據庫事務的概念,從而保證了即使多個浏覽器窗口操作同一數據,也不會產生沖突。

Web SQL Database 基本用法

  1. 創建和打開數據庫

使用數據庫的第一步是創建並打開數據庫,API 是 openDatabase。當數據庫已經存在時,openDatabase 僅僅打開數據庫;如果這個數據庫不存在,那麼就創建一個空數據庫並且打開它。openDatabase 的定義是:

  Database openDatabase(in DOMString name, in DOMString version,    in DOMString displayName, in unsigned long estimatedSize,    in optional DatabaseCallback creationCallback);  

name:數據庫名。

version:數據庫版本。

displayName:顯示名稱。

estimatedSize:數據庫預估長度(以字節為單位)。

creationCallback:回調函數。

  1. 執行事務處理

    在打開數據庫以後,就可以使用事務 API transaction。每一個事務作為操作數據庫的原子操作,不會被打斷,從而避免了數據沖突。transaction 的定義是:

     void transaction(in SQLTransactionCallback callback,   in optional SQLTransactionErrorCallback errorCallback,   in optional SQLVoidCallback successCallback);  

    callback:事務回調函數,其中可以執行 SQL 語句。

    errorCallback:出錯回調函數。

    successCallback:執行成功回調函數。

  2. 執行 SQL 語句

    在事務的回調函數 callback 中,可以執行 SQL 語句,API 是 executeSQL。executeSQL 的定義是:

      void executeSql(in DOMString sqlStatement,    in optional ObjectArray arguments, in optional SQLStatementCallback callback,    in optional SQLStatementErrorCallback errorCallback);  

    sqlStatement:SQL 語句。

    arguments:SQL 語句需要的參數。

    callback:回調函數。

    errorCallback:出錯回調函數。

Web SQL Database 示例

下面通過一個例子說明 Web SQL Database 的基本用法。它首先調用 openDatabase 創建了名為“fooDB”的數據庫。然後使用 transaction 執行兩條 SQL 語句。第一條 SQL 語句創建了名為“foo”的表,第二條 SQL 語句向表中插入一條記錄。


清單 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")');   });  

回頁首

離線應用示例

最後,通過一個例子來說明使用 Html5 開發離線應用的基本方法。這個例子會用到前面提到的離線資源緩存、在線狀態檢測和 DOM Storage 等功能。假設我們開發一個便簽管理的 Web 應用程序,用戶可以在其中添加和刪除便簽。它支持離線功能,允許用戶在離線狀態下添加、刪除便簽,並且當在線以後能夠同步到服務器上。

  1. 應用程序頁面

    這個程序的界面很簡單,如圖 1 所示。用戶點擊“New Note”按鈕可以在彈出框中創建新的便簽,雙擊某便簽就表示刪除它。



    圖 1. 應用程序頁面
    圖 1. 應用程序頁面 

    這個頁面的源文件是 index.Html,它的代碼如清單 8 所示。



    清單 8 頁面 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" onclick="newNote()">   <ul id="list"></ul>   </body>   </Html>  

    在 body 中聲明了一個按鈕和一個無序列表。當按下“New Note”按鈕時,newNote 函數將被調用,它用來添加一條新的便簽。而無序列表初始為空,它是用來顯示便簽的列表。

  2. cache manifest 文件

    定義 cache manifest 文件,聲明需要緩存的資源。在這個例子中,需要緩存“index.html”、“server.js”、“data.js”和“UI.JS”等 4 個文件。除了前面列出的“index.Html”外,“server.js”、“data.js”和“UI.JS”分別包含服務器相關、數據存儲和用戶界 面代碼。cache manifest 文件定義如下。



    清單 9 cache manifest 文件
    				   CACHE MANIFEST   index.Html   server.js   data.js   UI.JS  

  3. 用戶界面代碼

    用戶界面代碼定義在 UI.JS 中。



    清單 10 用戶界面代碼 UI.JS
    				   function newNote()   {      var title = window.prompt("New Note:");      if (title)      {          add(title);      }   }    function add(title)   {      // 在界面中添加     addUIItem(title);      // 在數據中添加     addDataItem(title);   }    function remove(title)   {      // 從界面中刪除     removeUIItem(title);      // 從數據中刪除     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 中的代碼包含添加便簽和刪除便簽的界面操作。

    • 添加便簽
    1. 用戶點擊“New Note”按鈕,newNote 函數被調用。
    2. newNote 函數會彈出對話框,用戶輸入新便簽內容。newNote 調用 add 函數。
    3. add 函數分別調用 addUIItem 和 addDataItem 添加頁面元素和數據。addDataItem 代碼將在後面列出。
    4. addUIItem 函數在頁面列表中添加一項。並指明 ondblclick 事件的處理函數是 remove,使得雙擊操作可以刪除便簽。
    • 刪除便簽
    1. 用戶雙擊某便簽時,調用 remove 函數。
    2. remove 函數分別調用 removeUIItem 和 removeDataItem 刪除頁面元素和數據。removeDataItem 將在後面列出。
    3. removeUIItem 函數刪除頁面列表中的相應項。
  4. 數據存儲代碼

    數據存儲代碼定義在 data.JS 中。



    清單 11 數據存儲代碼 data.JS
    				   var storage = window['localStorage'];    function addDataItem(title)   {      if (navigator.onLine) // 在線狀態     {          addServerItem(title);      }      else // 離線狀態     {          var str = storage.getItem("toAdd");          if(str == null)          {              str = title;          }          else          {              str = str + "," + title;          }          storage.setItem("toAdd", str);      }   }    function removeDataItem(title)   {      if (navigator.onLine) // 在線狀態     {          removeServerItem(title);      }      else // 離線狀態     {          var str = storage.getItem("toRemove");          if(str == null)          {              str = title;          }          else          {              str = str + "," + title;          }          storage.setItem("toRemove", str);      }   }      function SyncWithServer()   {      // 如果當前是離線狀態,不需要做任何處理     if (navigator.onLine == false)return;       var i = 0;      // 和服務器同步添加操作     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");      }       // 和服務器同步刪除操作     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);              // 從服務器獲取全部便簽,並顯示在界面中     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 中的代碼包含添加便簽、刪除便簽和與服務器同步等數據操作。其中用到了 navigator.onLine 屬性、online 事件、DOM Storage 等 Html5 新功能。

    • 添加便簽:addDataItem
    1. 通過 navigator.onLine 判斷是否在線。
    2. 如果在線,那麼調用 addServerItem 直接把數據存儲到服務器上。addServerItem 將在後面列出。
    3. 如果離線,那麼把數據添加到 localStorage 的“toAdd”項中。
    • 刪除便簽:removeDataItem
    1. 通過 navigator.onLine 判斷是否在線。
    2. 如果在線,那麼調用 removeServerItem 直接在服務器上刪除數據。removeServerItem 將在後面列出。
    3. 如果離線,那麼把數據添加到 localStorage 的“toRemove”項中。
    • 數據同步:SyncWithServer

    在 data.JS 的最後一行,注冊了 window 的 online 事件處理函數 SyncWithServer。當 online 事件發生時,SyncWithServer 將被調用。其功能如下。

    1. 如果 navigator.onLine 表示當前離線,則不做任何操作。
    2. 把 localStorage 中“toAdd”項的所有數據添加到服務器上,並刪除“toAdd”項。
    3. 把 localStorage 中“toRemove”項的所有數據從服務器中刪除,並刪除“toRemove”項。
    4. 刪除當前頁面列表中的所有便簽。
    5. 調用 getServerItems 從服務器獲取所有便簽,並添加在頁面列表中。getServerItems 將在後面列出。
  5. 服務器相關代碼

    服務器相關代碼定義在 server.JS 中。



    清單 12 服務器相關代碼 server.JS
    				   function addServerItem(title)   {      // 在服務器中添加一項  }    function removeServerItem(title)   {      // 在服務器中刪除一項  }    function getServerItems()   {      // 返回服務器中存儲的便簽列表  }  

    由於這部分代碼與服務器有關,這裡只說明各個函數的功能,具體實現可以根據不同服務器編寫代碼。

    • 在服務器中添加一項:addServerItem
    • 在服務器中刪除一項:removeServerItem
    • 返回服務器中存儲的便簽列表:getServerItems

回頁首

總結

本文介紹了 HTML5 為了支持離線應用程序新增的強大功能。通過閱讀本文,讀者能夠了解到 Html5 中離線相關特性的基本用法,從而掌握利用 Html5 開發 Web 離線應用的方法。


參考資料

  • W3C 的 Html5 規范:對 Html5 規范進行了全面描述。

  • WHATWG 主頁:WHATWG 是 Html5 規范的制定者。

  • Mozilla 離線應用:本文中的例子參考了它的實現。

  • Safari 離線應用開發指南:使用 Safari 開發離線應用的資料。

  • developerWorks Web development 專區:通過專門關於 Web 技術的文章和教程,擴展您在網站開發方面的技能。

  • developerWorks Ajax 資源中心:這是有關 Ajax 編程模型信息的一站式中心,包括很多文檔、教程、論壇、blog、wiki 和新聞。任何 AJax 的新信息都能在這裡找到。

  • developerWorks Web 2.0 資源中心,這是有關 Web 2.0 相關信息的一站式中心,包括大量 Web 2.0 技術文章、教程、下載和相關技術資源。您還可以通過Web 2.0 新手入門 欄目,迅速了解 Web 2.0 的相關概念。
XML學習教程| jQuery入門知識| AJAX入門| Dreamweaver教程| Fireworks入門知識| SEO技巧| SEO優化集錦|
Copyright © DIV+CSS佈局教程網 All Rights Reserved