【高级功能】使用Web存储
Web存储允许我们在浏览器里保存简单的键/值数据。Web存储和cookie很相似,但它有着更好的实现方式,能保存的数据量也很大。这两种类型共享相同的机制,但是被保存数据的可见性和寿命存在区别。
PS:还有一种存储规范名为“索引数据库API”(Indexed Database API),它允许保存富格式数据和进行SQL风格的查询。
1.使用本地存储
我们可以通过全局属性 localStorage访问本地存储功能。这个属性会返回一个Storage 对象,下表对其进行了介绍。Storage 对象被用来保存键/值形式的字符串对。
Storage 对象可用来存储键/值对,其中键和值都是字符串。键必须是惟一的,这就意味着如果我们用 Storage对象里已经存在的键调用setItem方法,就会更新它的值。下面的示例展示了如何添加、修改和清除本地存储中数据。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>使用本地存储</title> <style> body > * {float: left;} table {border-collapse: collapse;margin-left:50px; } th,td {padding: 4px;} th {text-align: right;} input {border: thin solid black;padding: 2px;} label {min-width: 50px;display: inline-block;text-align: right;} #countmsg,#buttons {margin-left: 50px;margin-top: 5px;margin-bottom: 5px;} </style> </head> <body> <div> <div><label>Key:</label><input id="key" placeholder="Enter Key" /></div> <div><label>Value:</label><input id="value" placeholder="Enter Value" /></div> <div id="buttons"> <button id="add">Add</button> <button id="clear">Clear</button> </div> <p id="countmsg">These are <span id="count"></span> items </p> </div> <table id="data" border="1"> <tr><th>Item Count:</th><td id="count">-</td> </tr> </table> <script> displayData(); var buttons = document.getElementsByTagName("button"); for(var i=0;i<buttons.length;i++){ buttons[i].onclick = handleButtonPress; } function handleButtonPress(e){ switch (e.target.id){ case 'add': var key = document.getElementById("key").value; var value = document.getElementById("value").value; localStorage.setItem(key,value); displayData(); break; case 'clear': localStorage.clear(); displayData(); break; } } function displayData(){ var tableElem = document.getElementById("data"); tableElem.innerHTML = ""; var itemCount = localStorage.length; document.getElementById("count").innerHTML = itemCount; for(var i=0;i<itemCount;i++){ var key = localStorage.key(i); var val = localStorage[key]; tableElem.innerHTML += "<tr><th>" + key + ":</th><td>" + val + "</td></tr>"; } } </script> </body> </html>
此例报告了本地存储中的项目数量,并枚举已保存的键/值对来填充一个表格元素。这里添加了两个button元素,在Add按钮被按下时将他们的内容保存为项目。在响应Clear按钮时,会清除本地存储中的内容。其显示效果如下:
浏览器不会删除我们用 localStorage对象添加的数据,除非用户自己清除浏览数据。
监听存储事件
通过本地存储功能保存的数据对所有来源相同的文档都是可用的。某个文档对本地存储进行修改时会触发storage事件,我们可以监听其他同源文档上的这个事件来确保我们能跟上最新的变化。
与storage事件同时指派的对象是一个StorageEvent对象,它的成员如下表所示:
下面的示例展示了一个文档,它会监听并编录本地存储对象上触发的事件。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>编录本地存储事件</title> <style> table {border-collapse:collapse; } th,td {padding: 4px;} </style> </head> <body> <table id="data" border="1"> <tr> <th>key</th> <th>oldValue</th> <th>newValue</th> <th>url</th> <th>storageArea</th> </tr> </table> <script> var tableElem = document.getElementById("data"); window.onstorage = handleStorage; function handleStorage(e){ var row = "<tr>"; row += "<td>" + e.key + "</td>"; row += "<td>" + e.oldValue + "</td>"; row += "<td>" + e.newValue + "</td>"; row += "<td>" + e.url + "</td>"; row += "<td>" + (e.storageArea == localStorage) + "</td>"; row += "</tr>"; tableElem.innerHTML += row; } </script> </body> </html>
storage事件是通过Window对象触发的,此对象可以来自共享被改动存储的任何一个文档。此例中,每次接收到事件时都会给table元素添加一个新行,演示效果如下:
图中的事件展示了给本地存储添加新项目的过程。url属性能帮助我们了解是哪个文档触发了变化。storageArea属性会返回发生变化的Storage对象,它可以是本地或会话存储对象。此例只接收来自本地存储对象的事件。
PS:这些事件不会再制造变化的文档内指派。
2. 使用会话存储
会话存储(session storage)的工作方式和本地存储很接近,不同之处在于数据是各个浏览上下文私有的,会在文档被关闭时移除。我们通过全局变量 sessionStorage访问会话存储,它会返回一个Storage对象。下面的例子展示了会话存储的用法:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>使用会话存储</title> <style> body > * {float: left;} table {border-collapse: collapse;margin-left:50px; } th,td {padding: 4px;} th {text-align: right;} input {border: thin solid black;padding: 2px;} label {min-width: 50px;display: inline-block;text-align: right;} #countmsg,#buttons {margin-left: 50px;margin-top: 5px;margin-bottom: 5px;} </style> </head> <body> <div> <div><label>Key:</label><input id="key" placeholder="Enter Key" /></div> <div><label>Value:</label><input id="value" placeholder="Enter Value" /></div> <div id="buttons"> <button id="add">Add</button> <button id="clear">Clear</button> </div> <p id="countmsg">These are <span id="count"></span> items </p> </div> <table id="data" border="1"> <tr><th>Item Count:</th><td id="count">-</td> </tr> </table> <script> displayData(); var buttons = document.getElementsByTagName("button"); for(var i=0;i<buttons.length;i++){ buttons[i].onclick = handleButtonPress; } function handleButtonPress(e){ switch (e.target.id){ case 'add': var key = document.getElementById("key").value; var value = document.getElementById("value").value; sessionStorage.setItem(key,value); displayData(); break; case 'clear': sessionStorage.clear(); displayData(); break; } } function displayData(){ var tableElem = document.getElementById("data"); tableElem.innerHTML = ""; var itemCount = sessionStorage.length; document.getElementById("count").innerHTML = itemCount; for(var i=0;i<itemCount;i++){ var key = sessionStorage.key(i); var val = sessionStorage[key]; tableElem.innerHTML += "<tr><th>" + key + ":</th><td>" + val + "</td></tr>"; } } </script> </body> </html>
此例的工作方式和前面本地存储的例子很接近,不同之处在于可见性和寿命受到限制。这些限制会影响storage事件的处理方式:前面提到的storage事件只会在共享存储的文档中触发。对于会话存储,这就意味着事件只会在内嵌文档中触发,比如 iframe里的文档。修改前一示例如下:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>使用会话存储的storage事件</title> <style> body > * {float: left;} table {border-collapse: collapse;margin-left:50px; } th,td {padding: 4px;} th {text-align: right;} input {border: thin solid black;padding: 2px;} label {min-width: 50px;display: inline-block;text-align: right;} #countmsg,#buttons {margin-left: 50px;margin-top: 5px;margin-bottom: 5px;} iframe {clear: left;} </style> </head> <body> <div> <div><label>Key:</label><input id="key" placeholder="Enter Key" /></div> <div><label>Value:</label><input id="value" placeholder="Enter Value" /></div> <div id="buttons"> <button id="add">Add</button> <button id="clear">Clear</button> </div> <p id="countmsg">These are <span id="count"></span> items </p> </div> <table id="data" border="1"> <tr><th>Item Count:</th><td id="count">-</td> </tr> </table> <br /> <iframe src="storage-02.html" width="666" height="222"></iframe></div> <script> displayData(); var buttons = document.getElementsByTagName("button"); for(var i=0;i<buttons.length;i++){ buttons[i].onclick = handleButtonPress; } function handleButtonPress(e){ switch (e.target.id){ case 'add': var key = document.getElementById("key").value; var value = document.getElementById("value").value; sessionStorage.setItem(key,value) displayData(); break; case 'clear': sessionStorage.clear(); displayData(); break; } } function displayData(){ var tableElem = document.getElementById("data"); tableElem.innerHTML = ""; var itemCount = sessionStorage.length; document.getElementById("count").innerHTML = itemCount; for(var i=0;i<itemCount;i++){ var key = sessionStorage.key(i); var val = sessionStorage[key]; tableElem.innerHTML += "<tr><th>" + key + ":</th><td>" + val + "</td></tr>"; } } </script> </body> </html>
其演示效果如下: