HTML5新特性之離線快取技術實戰
八、離線Web應用實戰。
通過一個簡單的記事本程式——PermaNote,來解釋如何使用。程式將使用者的文字儲存到localStorage中,並且在網路連線可用的時候,
將其上傳到伺服器,PermaNote只允許使用者編輯單個筆記。
PermaNote應用包含3個檔案,一個應用清單檔案、一個html頁面檔案,一個實現邏輯的js檔案。
Demo: http://xuanfengge.com/demo/201506/appcache/permanote.html
①.premanote.appcache部分:
CACHE MANIFEST
# PermaNote v8
permanote.html
permanote.js
NETWORK:
note
②.permanote.html部分:
<!DOCTYPEHTML> <html manifest= permanote.appcache”> <head> <title>PermaNote Editor</title> <script src=” permanote.js”></script> <style type=”text/css”> #editor {width:100%;height:250px} #statusline{width:100%} </style> </head> <body> <div id=”toobar”> <button id=”savebutton”onclick = “save()”>save</button> <button onclick = “sync()”>SyncNote</button> <button onclick = “applicationCache.update()”>UpdateApplication</button> <textarea id=”editor”></textarea> <div id=”statusline”></div> </div> </body> </html>
③.permanote.js部分
status()函式用於顯示狀態列訊息,save()函式將筆記本儲存到伺服器,sync()用於確保本地與伺服器文字的同步。
應用程式的時間處理程式解釋:
(1).onload
嘗試和伺服器同步,一旦有新版本的筆記並且完成同步後,就啟用編輯器視窗。
save()和sync()函式發出HTTP請求,並在XMLHttpRequest物件上註冊一個onload時間處理程式來獲取上傳或者
下載完成的提醒。
(2).onbeforeunload
在未上傳前,把當前版本的筆記資料儲存到伺服器上。
(3).oninput
每當textarea輸入框內容發生變化時,都將其內容儲存到localStorage中,並啟動一個計時器。當用戶停止編輯超過5秒
,將自動把資料儲存到伺服器。
(4).onoffline
當瀏覽器進入離線狀態時,在狀態列顯示離線訊息。
(5).ononline
當瀏覽器回到線上狀態時,同步伺服器,檢查是否有新版本的資料,並且儲存當前版本的資料。
(6).onupdateready
如果新版本的應用已快取,則在狀態列展示訊息告知使用者。
(7).onnoupdate
// 定義全域性變數
var editor, statusline, savebutton, idletimer;
// 首次載入應用
window.onload = function() {
// 第一次載入時,初始化本地儲存
if (localStorage.note == null) localStorage.note = "";
if (localStorage.lastModified == null) localStorage.lastModified = 0;
if (localStorage.lastSaved == null) localStorage.lastSaved = 0;
// 查詢編輯器UI元素,並初始化全域性變數
editor = document.getElementById("editor");
statusline = document.getElementById("statusline");
savebutton = document.getElementById("savebutton");
editor.value = localStorage.note; // 初始化編輯器,將儲存的筆記資料填充到內容
editor.disabled = true; // 同步前禁止編輯
// 當輸入框內容發生變化
editor.addEventListener("input",
function (e) {
// 將新的內容儲存至localStorage
localStorage.note = editor.value;
localStorage.lastModified = Date.now();
// 重置閒置計時器
if (idletimer) clearTimeout(idletimer);
idletimer = setTimeout(save, 5000);
// 啟用儲存按鈕
savebutton.disabled = false;
},
false);
// 每次載入應用程式時,嘗試同步伺服器
sync();
};
// 離開頁面錢儲存資料到伺服器
window.onbeforeunload = function() {
if (localStorage.lastModified > localStorage.lastSaved)
save();
};
// 離線時,告知使用者
window.onoffline = function() { status("Offline"); }
// 再次返回線上狀態時,進行同步
window.ononline = function() { sync(); };
// 當有新版本應用的時候,提醒使用者
// 也可使用location.reload()放大來強制重新整理應用
window.applicationCache.onupdateready = function() {
status("A new version of this application is available. Reload to run it");
};
// 當沒有新版本的時候也通知使用者
window.applicationCache.onnoupdate = function() {
status("You are running the latest version of the application.");
};
// 狀態列顯示相關資訊提示
function status(msg) { statusline.innerHTML = msg; }
// 每當筆記本內容更新後,如果使用者停止編輯超過5分鐘
// 就會自動將筆記文字上傳至伺服器(線上狀態下)
function save() {
if (idletimer) clearTimeout(idletimer);
idletimer = null;
if (navigator.onLine) {
var xhr = new XMLHttpRequest();
xhr.open("PUT", "/note");
xhr.send(editor.value);
xhr.onload = function() {
localStorage.lastSaved = Date.now();
savebutton.disabled = true;
};
}
}
// 檢查服務端是否有新版本的筆記,若無,則將當前版本儲存到伺服器端
function sync() {
if (navigator.onLine) {
var xhr = new XMLHttpRequest();
xhr.open("GET", "/note");
xhr.send();
xhr.onload = function() {
var remoteModTime = 0;
if (xhr.status == 200) {
var remoteModTime = xhr.getResponseHeader("Last-Modified");
remoteModTime = new Date(remoteModTime).getTime();
}
if (remoteModTime > localStorage.lastModified) {
status("Newer note found on server.");
var useit =
confirm("There is a newer version of the note\n" +
"on the server. Click Ok to use that version\n"+
"or click Cancel to continue editing this\n"+
"version and overwrite the server");
var now = Date.now();
if (useit) {
editor.value = localStorage.note = xhr.responseText;
localStorage.lastSaved = now;
status("Newest version downloaded.");
}
else
status("Ignoring newer version of the note.");
localStorage.lastModified = now;
}
else
status("You are editing the current version of the note.");
if (localStorage.lastModified > localStorage.lastSaved) {
save();
}
editor.disabled = false; // 再次啟用編輯器
editor.focus(); // 將游標定位到編輯器中
}
}
else { // 離線狀態下,不能同步
status("Can't sync while offline");
editor.disabled = false;
editor.focus();
}
}