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

html5 storage api

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

为什么要有 storage ?

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

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

storage 类型

storage 一共有两种

  1. localStorage

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

  2. sessionStorage

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

两个 storage 的 api 很相似,下面以 localStorage 为例

localStorage 演示

基础 api

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

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

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

以上是 storage 的 api

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

类对象操作

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

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);
}

上述的写法是错误的,因为 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.html 和 test2.html 都设置了 storage 监听事件,且同源。

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

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

  1. setItem
  2. getItem
  3. removeItem

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

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

总结

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

posted @ 2021-02-13 18:59  Huro~  阅读(334)  评论(0)    收藏  举报