localStorage支持還算廣泛,ie8都有支持,存儲量多數(shù)≈5M,也還可以,但是要是存儲圖片和文件,感覺就有些捉襟見肘,不過如有需要還是了解一下這方面的技術(shù)比較好。
你可能已經(jīng)對本地存儲有所了解,本地存儲在瀏覽器中快速存儲數(shù)據(jù)的時候特別強大,并且已經(jīng)在瀏覽器中存在多時。但是如何才能在本地存儲中保存文件呢? 首先,推薦你先閱讀 Storing images and files in IndexedDB 。 使用JSON實現(xiàn)強大的本地存儲控制首先,我們先了解一些基本的本地存儲相關(guān)的知識。你可以使用鍵值對的方式往本地存儲中存儲數(shù)據(jù),就像這樣: localStorage.setItem("name", "Robert"); 而從本地存儲中讀取數(shù)據(jù)的方式如下: localStorage.getItem("name"); 這樣的存取方式非常不錯,而且最多可以存儲5M的數(shù)據(jù),給你更多選擇的空間。但是由于本地存儲是基于字符串的存儲,存儲一串沒有結(jié)構(gòu)的字符串并不是一個理想的選擇。因此,我們可以利用瀏覽器中原生的JSON支持來將JavaScript對象轉(zhuǎn)化成字符串,從而保存到本地數(shù)據(jù)中,在讀取的時候也可以將其轉(zhuǎn)換回JavaScript對象。 圖片的存儲我們的想法是做到將已經(jīng)當前頁面中已緩存的圖片保存到本地存儲中。不過就像我們之前已經(jīng)確定的,本地存儲只支持字符串的存取,那么我們要做的就是將圖片轉(zhuǎn)換成 Data URI 。其中一種實現(xiàn)方式就是用canvas元素來加載圖片。然后你可以以Data URI的形式從canvas中讀取出當前展示的內(nèi)容。 讓我們看一個例子。 //當圖片加載完成的時候觸發(fā)回調(diào)函數(shù) elephant.addEventListener("load", function () { var imgCanvas = document.createElement("canvas"), imgContext = imgCanvas.getContext("2d"); // 確保canvas元素的大小和圖片尺寸一致 imgCanvas.width = elephant.width; imgCanvas.height = elephant.height; // 渲染圖片到canvas中 imgContext.drawImage(elephant, 0, 0, elephant.width, elephant.height); // 用data url的形式取出 var imgAsDataURL = imgCanvas.toDataURL("image/png"); // 保存到本地存儲中 try { localStorage.setItem("elephant", imgAsDataURL); } catch (e) { console.log("Storage failed: " + e); } }, false); 如果我們想要考慮地更長遠一些,那么還可以利用JavaScript對象并做一些數(shù)據(jù)檢查。在這個例子中,第一次我們從服務(wù)端讀取圖片,之后每一次頁面加載時,我們就可以直接從本地存儲中讀取已讀取過的圖片。 HTML部分<figure> <img id="elephant" src="about:blank" alt="A close up of an elephant"> <noscript> <img src="elephant.png" alt="A close up of an elephant"> </noscript> <figcaption>A mighty big elephant, and mighty close too!</figcaption> </figure> JavaScript部分//在本地存儲中保存圖片 var storageFiles = JSON.parse(localStorage.getItem("storageFiles")) || {}, elephant = document.getElementById("elephant"), storageFilesDate = storageFiles.date, date = new Date(), todaysDate = (date.getMonth() + 1).toString() + date.getDate().toString(); // 檢查數(shù)據(jù),如果不存在或者數(shù)據(jù)過期,則創(chuàng)建一個本地存儲 if (typeof storageFilesDate === "undefined" || storageFilesDate < todaysDate) { // 圖片加載完成后執(zhí)行 elephant.addEventListener("load", function () { var imgCanvas = document.createElement("canvas"), imgContext = imgCanvas.getContext("2d"); // 確保canvas尺寸和圖片一致 imgCanvas.width = elephant.width; imgCanvas.height = elephant.height; // 在canvas中繪制圖片 imgContext.drawImage(elephant, 0, 0, elephant.width, elephant.height); // 將圖片保存為Data URI storageFiles.elephant = imgCanvas.toDataURL("image/png"); storageFiles.date = todaysDate; // 將JSON保存到本地存儲中 try { localStorage.setItem("storageFiles", JSON.stringify(storageFiles)); } catch (e) { console.log("Storage failed: " + e); } }, false); // 設(shè)置圖片 elephant.setAttribute("src", "elephant.png"); } else { // Use image from localStorage elephant.setAttribute("src", storageFiles.elephant); } 注意:此處需要注意本地存儲的容量,最好使用try…catch來控制異常。 保存任意格式的文件使用canvas將圖片轉(zhuǎn)換成Data URI并保存到本地存儲中的方式非常好,但是如果我們希望能找到一個可以保存任意格式文件的方式。 那么,這個過程就顯的比較有趣了,我們需要用到:
基本方法是:
// 獲取文件 var rhinoStorage = localStorage.getItem("rhino"), rhino = document.getElementById("rhino"); if (rhinoStorage) { //如果已經(jīng)存在則直接重用已保存的數(shù)據(jù) rhino.setAttribute("src", rhinoStorage); } else { // 創(chuàng)建XHR, BlobBuilder 和FileReader 對象 var xhr = new XMLHttpRequest(), blobBuilder = new (window.BlobBuilder || window.MozBlobBuilder || window.WebKitBlobBuilder || window.OBlobBuilder || window.msBlobBuilder), blob, fileReader = new FileReader(); xhr.open("GET", "rhino.png", true); //將響應(yīng)頭類型設(shè)置為“arraybuffer”,也可以使用"blob",這樣就不需要使用BlobBuilder來構(gòu)建數(shù)據(jù),但是"blob"的支持程度有限。 xhr.responseType = "arraybuffer"; xhr.addEventListener("load", function () { if (xhr.status === 200) { // 將響應(yīng)數(shù)據(jù)放入blobBuilder中 blobBuilder.append(xhr.response); // 用文件類型創(chuàng)建blob對象 blob = blobBuilder.getBlob("image/png"); // 由于Chrome不支持用addEventListener監(jiān)聽FileReader對象的事件,所以需要用onload fileReader.onload = function (evt) { // 用Data URI的格式讀取文件內(nèi)容 var result = evt.target.result; // 將圖片的src指向Data URI rhino.setAttribute("src", result); //保存到本地存儲中 try { localStorage.setItem("rhino", result); } catch (e) { console.log("Storage failed: " + e); } }; // 以Data URI的形式加載blob fileReader.readAsDataURL(blob); } }, false); // 發(fā)送異步請求 xhr.send(); } 使用“blob”作為響應(yīng)頭類型在上面的例子中,我們使用的是“arraybuffer”作為響應(yīng)頭類型,然后使用BlobBuilder來創(chuàng)建可以由FileReader讀取的數(shù)據(jù)。然而,”blob”作為響應(yīng)頭類型后,會直接返回一個blob對象,從而可以直接由FileReader讀取。上面的例子可以改成這樣: // Getting a file through XMLHttpRequest as an arraybuffer and creating a Blob var rhinoStorage = localStorage.getItem("rhino"), rhino = document.getElementById("rhino"); if (rhinoStorage) { // Reuse existing Data URL from localStorage rhino.setAttribute("src", rhinoStorage); } else { // Create XHR, BlobBuilder and FileReader objects var xhr = new XMLHttpRequest(), fileReader = new FileReader(); xhr.open("GET", "rhino.png", true); // Set the responseType to arraybuffer. "blob" is an option too, rendering BlobBuilder unnecessary, but the support for "blob" is not widespread enough yet xhr.responseType = "blob"; xhr.addEventListener("load", function () { if (xhr.status === 200) { // onload needed since Google Chrome doesn't support addEventListener for FileReader fileReader.onload = function (evt) { // Read out file contents as a Data URL var result = evt.target.result; // Set image src to Data URL rhino.setAttribute("src", result); // Store Data URL in localStorage try { localStorage.setItem("rhino", result); } catch (e) { console.log("Storage failed: " + e); } }; // Load blob as Data URL fileReader.readAsDataURL(xhr.response); } }, false); // Send XHR xhr.send(); } 瀏覽器支持情況
|
|