客户端保存数据

采用 JavaScript 代码的简单 HTML 页面可以作为实现一些小应用的很好的途径。可以采用小的帮助程序来自动化一些基本的任务。通过关联一些表单字段和事件处理器,你可以实现华氏度与摄氏度的转换。也可以实现由主密码和网站名来生成密码等各种任务。

当一个应用需要存储一些东西以便于跨对话使用时,则不能使用 JavaScript 绑定因为每当页面关闭时这些值就会丢失。你可以搭建一个服务器,连接到因特网,将一些服务数据存储到其中。在第20章中将会介绍如何实现这些,当然这需要很多的工作,也有一定的复杂度。有时只要将数据存储在浏览器中即可。

localStorage对象可以用于保存数据,它在页面重新加载后还存在。这个对象允许你将字符串存储在某个名字(也是字符串)下,下面是具体示例。

  1. localStorage.setItem("username", "marijn");
  2. console.log(localStorage.getItem("username"));
  3. // → marijn
  4. localStorage.removeItem("username");

一个在localStorage中的值会保留到其被重写时,它也可以通过removeItem来清除,或者由用户清除本地数据。

不同字段名的站点的数据会存在不同的地方。这也表明原则上由localStorage存储的数据只可以由相同站点的脚本编辑。

浏览器的确限制一个站点可以存储的localStorage的数据大小。这种限制,以及用垃圾填满人们的硬盘并不是真正有利可图的事实,防止该特性占用太多空间。

下面的代码实现了一个粗糙的笔记应用。程序将用户的笔记保存为一个对象,将笔记的标题和内容字符串相关联。对象被编码为 JSON 格式并存储在localStorage中。用户可以从<select>选择字段中选择笔记并在<textarea>中编辑笔记,并可以通过点击一个按钮来添加笔记。

  1. Notes: <select></select> <button>Add</button><br>
  2. <textarea style="width: 100%"></textarea>
  3. <script>
  4. let list = document.querySelector("select");
  5. let note = document.querySelector("textarea");
  6. let state;
  7. function setState(newState) {
  8. list.textContent = "";
  9. for (let name of Object.keys(newState.notes)) {
  10. let option = document.createElement("option");
  11. option.textContent = name;
  12. if (newState.selected == name) option.selected = true;
  13. list.appendChild(option);
  14. }
  15. note.value = newState.notes[newState.selected];
  16. localStorage.setItem("Notes", JSON.stringify(newState));
  17. state = newState;
  18. }
  19. setState(JSON.parse(localStorage.getItem("Notes")) || {
  20. notes: {"shopping list": "Carrots\nRaisins"},
  21. selected: "shopping list"
  22. });
  23. }
  24. list.addEventListener("change", () => {
  25. setState({notes: state.notes, selected: list.value});
  26. });
  27. note.addEventListener("change", () => {
  28. setState({
  29. notes: Object.assign({}, state.notes,
  30. {[state.selected]: note.value}),
  31. selected: state.selected
  32. });
  33. });
  34. document.querySelector("button")
  35. .addEventListener("click", () => {
  36. let name = prompt("Note name");
  37. if (name) setState({
  38. notes: Object.assign({}, state.notes, {[name]: ""}),
  39. selected: name
  40. });
  41. });
  42. </script>

脚本从存储在localStorage中的"Notes"值来获取它的初始状态,如果其中没有值,它会创建示例状态,仅仅带有一个购物列表。从localStorage中读取不存在的字段会返回null

setState方法确保 DOM 显示给定的状态,并将新状态存储到localStorage。 事件处理器调用这个函数来移动到一个新状态。

在这个例子中使用Object.assign,是为了创建一个新的对象,它是旧的state.notes的一个克隆,但是添加或覆盖了一个属性。 Object.assign选取第一个参数,向其添加所有更多参数的所有属性。 因此,向它提供一个空对象会使它填充一个新对象。 第三个参数中的方括号表示法,用于创建名称基于某个动态值的属性。

还有另一个和localStorage很相似的对象叫作sessionStorage。这两个对象之间的区别在于sessionStorage的内容会在每次会话结束时丢失,而对于多数浏览器来说,会话会在浏览器关闭时结束。