一篇文章图文并茂地带你轻松学会 HTML5 storage

html5 storage api

localStoragesessionStoragehtml5 新增的用来存储数据的对象,他们让我们可以以键值对的形式存储信息。

为什么要有 storage ?

我们已经有了 session 可以帮助我们存储信息,为何还需要 storage 呢?

  1. 各个浏览器的 cookie 长度大概只能在 4kb 左右,而 storage 大概能达到 5M,这意味着可以存储更多的信息
  2. cookie 可以被后端更改,在每次进行网络请求的时候都会被发送给服务器,而 storage 不会,这意味着这个存储是完全受控于前端(JavaScript)的。

storage 类型

storage 一共有两种

  1. localStorage

    这个存储对象的存储和 origin 有关,即只要是同域名同协议同端口,存储是共享的。尽管关机了,或是关掉浏览器了,只要打开同源网站,存储的数据会依然存在,数据不会过期消失。

  2. sessionStorage

    这个存储对象的存储是暂时的,只保持在当前会话中,简单来说就是和浏览器的一个 tab 有关,只要 tab 关掉了再打开数据就没了,但是在当前界面刷新的话,数据就还在(这个时候认为是一个 tab)。

两个 storageapi 很相似,下面以 localStorage 为例

localStorage 演示

基础 api

localStorage.setItem("name", "huro"); // 设置键值对

一篇文章图文并茂地带你轻松学会 HTML5 storage

可以在 chrome 浏览器的控制台进行观察,这里已经设置上去了。下面也可以做相应的测试。

localStorage.getItem("name"); // huro
localStorage.removeItem("name"); // 删除某个键
localStorage.clear(); // 删除所有键值对
localStorage.key(0); // 获得索引为 0 的key
localStorage.length; // 获得 `localStroage` 的键的个数

以上是 storageapi

唯一需要注意的是 key(index) 这个 apikey 被设置的先后是没有关系的。

类对象操作

也可以用类对象的方法操作

localStorage.name = "huro";
console.log(localStorage.name); // huro
delete localStorage.name; // 删除键

但是上面的做法不推荐,如果用的是某些特殊的 key 例如 length 就会报错,因为原先 localStorage.length 表示获得键值对长度,理应是不能修改的。

localStorage["length"] = 4; // 修改无效

因此不推荐用这个做法修改 storage

遍历键值

由于 storage 并没有 Symbol.iterator 属性,这意味着 storage 不能用 for of循环遍历。以下有三种遍历方式。

假设我们只有一个键值对 name: huro

  1. for in 循环
for (let key in localStorage) {
    console.log(key);
}

一篇文章图文并茂地带你轻松学会 HTML5 storage

上述的写法是错误的,因为 for in 循环会遍历原型链上的属性和方法,因此需要稍作改善。

for (let key in localStorage) {
  if (!localStorage.hasOwnProperty(key)) {
    continue;
  }
  console.log(key);
}

这个时候就能正确的只打印出键 name

  1. 简单 for 循环
for(let i = 0; i < localStorage.length; i+= 1) {
  let key = localStorage.key(i);
  console.log(key);
}

这个时候能正确的只打印出键 name

  1. Object.keys()

这个方法会获得某个对象自身的 key,而不会管原型链上的

const keys = Object.keys(localStorage);
for(let key of keys) {
  alert(key);
}

而且获得的 key 是数组,具有 iterator 因此可以用 for of 遍历

这个时候能正确的只打印出键 name

只能是 string

storage 被设计出来比较不足的地方是,键和值都只能是 string 类型的,如果不是的话,会自动转换成 string

由于是隐式转换,初学者往往不知道,这意味着可能带来一些 bug

localStorage.user = { name: "huro" };
console.log(localStorage.user); // [object Object]

上述代码在存储 user 的时候,被自动调用 toString 方法,转化为了 [object Object]

storage 事件

storage 事件返回一个对象,里面包含几个参数

  1. key 改变的键
  2. oldValue => 旧值 || null
  3. newValue => 新值 || null
  4. url 触发这个事件的 url 地址
  5. storageArea 要么是 localStorage 要么是 sessionStorage 取决与是更改哪个storage
// 1.html
window.addEventListener("storage", (state) => {
    console.log(state.key, state.value, state.url); // name huro ./2.html(实际 url 是绝对路径)
})

// 2.html
localStorage.setItem("name", "huro");

还记得我们之前说过, localStorage 只要是同源都可以分享吗,这意味如果我们打开了两个窗口,只要他们是同源的,我们可以用上述的监听事件,监听另一个端口修改 storage,也就是可以实现不同的窗口之间的数据共享。

注意: 经测试,chrome edge 等现代浏览器不会触发自身文件或同文件的 storage 事件,即必须是两个不同的 html 才会互相触发。

例如 test1.htmltest2.html 都设置了 storage 监听事件,且同源。

test1.htmlstorageapi 事件会触发 test2.html 的,但是不能触发本身的 storage 监听事件。

另外这里的 api 事件也有限制,经过笔者测试,似乎只有

  1. setItem
  2. getItem
  3. removeItem

有效果,而 clear 事件是没有效果的。
上面全程用 localStorage 演示,

sessionStorage 也是类似的,读者有兴趣可以自行码一下代码。

总结

storage 是很好的一个 html5 特性,让我们方便快捷的存储数据,美中不足的是只能存储字符型数据,不过也很容易解决这个问题。同时利用监听事件,也可以实现不同窗口之间的广播机制。是非常实用的一个特性。

上一篇:The Swift Programming Language-官方教程精译Swift(9) 枚举-- --Enumerations


下一篇:解决Vue页面刷新数据丢失