xj.storage 本地存储操作

基本介绍

简介 : xj.storage 是一个关于本地存储的插件,它对 localStoragesessionStorage 这两个对象的内容进行了一些扩展,使用该插件有以下好处,首先是它在操作时全程使用了 try…catch 容错处理,可避免存储操作出错后逻辑被卡住的危险,其次是它借助了 JSON 对数据格式进行了转存,使得存储不再局限于字符串,最后是它修复了许多浏览器的 BUG,使得存储操作变得更加统一和安全。

兼容 : IE10+ / Edge12+ / Firefox / Chrome / Safari / Opera / IOS Webkit / Android Platform

更新 : https://github.com/xjZone/xj.storage/blob/master/upgrade.md

源码 : https://github.com/xjZone/xj.storage/

协议 : Apache License 2.0

版本 :


引入插件

首先是引入相关的文件,推荐使用带 immutableJSDelivr CDN:


xj.storage.localStorage

localStorage 相关的属性与方法都被设置在了 xj.storage.localStorage 对象上,实际上这个调用确实是太长了,所以建议在使用时先进行简化,例如用 var xjls = xj.storage.localStorage;xj.ls = xj.storage.localStorage; 的写法,缩短后再使用,此外就是 xj.storage.localStorage 对象和 xj.storage.sessionStorage 对象的属性与方法都是一样的,只在 Storage 事件的响应方面略有区别,关于事件的这个区别我们最后会再讲到,下面我们主要以 xj.storage.localStorage 对象的内容来做示范。


.set()

该方法类似 localStorage.setItem() 方法,但是它会用借助 JSON 对数据进行转存,所以能够支持多种数据类型,而不是仅限于字符串,由于 JSON 需要考虑跨语言的兼容性,所以它并不支持其他语言没有的数据类型(如 undefined),以下是支持和转换的细节:

Number => 支持,但是 NaNInfinity 等特殊值会被转成 null
String => 支持,任意的字符串都是可以的。
Boolean => 支持。
Object => 支持,但非简单对象会被转成空对象,不被支持的键值对则会直接忽略。
Array => 支持,但数组中的元素如果是非法值,将会被转成 null
null => 支持,没有目标值的时候就是返回 null
undefined => 不支持,默认情况下直接存储将变成 null,在数组中存储也会变成 null,在对象中存储则会被忽视。
Function => 不支持,默认情况下直接存储将变成 null,在数组中存储也会变成 null,在对象中存储则会被忽视。
Symbol => 不支持,默认情况下直接存储将变成 null,在数组中存储也会变成 null,在对象中存储则会被忽视。
BigInt => 不支持,存储将失败,如果你确实有这种需求,也许可以考虑先转 String,获取时再转回 BigInt

语法 : xj.storage.localStorage.set(key, value)
    key : Required | String | 键名,禁止设置 constructortoString 等原形对象上已经存在的键名
    value : Required | Anytype | 结果,UndefinedFunctionSymbolBigInt 都不被支持


.get()

该方法类似于 localStorage.getItem() 方法,但是它会用借助 JSON 对结果进行解析,所以可得到各种数据类型的值,该方法的第二个参数既 defaultValue 用于设置一个默认值,当 Storage 操作出错或目标值并不存在时,就会得到这个默认值,默认为 null

语法 : xj.storage.localStorage.get(key[, defaultValue])
    key : Required | String | 键名,如果目标并不存在则返回 defaultValue
    defaultValue : Optional | Anytype | 默认值,当出错或目标值不存在时返回该值,默认为 null


.remove()

该方法类似于 localStorage.removeItem() 方法,用于移除目标键值对,该方法没有返回值,即使被移除的目标不存在也不会报错。


.clear()

该方法类似 localStorage.clear() 方法,用于清空 localStorage,但是将操作放在了 try…catch 中,避免因为出错而卡住。


.length()

该方法类似 localStorage.length 属性,只是将操作放在了 try…catch 中,避免因为出错而卡住,如果出错了则总是返回 0


.key()

该方法类似 localStorage.key() 方法,传入索引值后会返回目标位置的 key 值,但需要注意的是,排序未必和存入的顺序相同。


.byte()

该方法用于获取 localStorage 存储数据的总字节数,要注意的是这个字节数是包括 valuekey 的,而不是只计算 value


.error

该属性用于保存操作出错时的错误对象,默认为 null,它会保存最近的一个错误,对于一些关键操作,你可以在操作后就判断,如果这个属性不为 null,那就表示出错了,得进行容错处理,之后就得将这个属性再设置为 null,否则可能会影响到之后的操作判断。


.support

该属性用于判断浏览器是否支持 localStorage 对象和它的属性与方法,支持返回 true,否则返回 false,由于插件做了容错处理,所以即使返回 false,操作无法运行也不会卡住 JS,只是功能会无效化,不支持的情况多种多样,可参考 XJ 写的 这篇文章


.listener

该属性用于记录 on() 方法绑定的事件监听,关于该方法和 Storage 事件的绑定,下一章就会提到了,这个属性是个数组,元素都是对象,结构为 {key:String, callback:Function},当使用了 off() 方法进行事件移除时,这个数组中对应的元素也会被删掉。


.on()

该方法用于绑定 Storage 事件,被监听的 key 在发生变化的时候就会触发事件,与原生的 Storage 事件相比,该方法解决了 IE 浏览器中的一些兼容问题,并且 Storage 事件会在所有的页面中触发,包括操作数据的页面也会触发该事件,虽然按照标准,导致数据变化的那个页面不该响应这个事件的,如果你还是希望跟标准保持一致,那么可通过全局配置的 dispatchOriginal 参数进行修改。

语法 : xj.storage.localStorage.on(key, callback)
    key : Required / String / 要监听变化的目标 key
    callback : Required / Function / 回调,函数还有个 event 参数


.off()

该方法用于解绑 Storage 事件,解绑后目标 key 在发生变化的时候就不会再响应事件了,它可以接受两个参数,但只有第一个参数是必填项,如果只传入了第一个参数,那么所有符合该参数的事件都会被解绑,如果还传入了第二个参数,那么就只有那些既符合 key 参数又符合 callback 参数的事件才会被解绑,on() 方法可执行多次监听同个 key 值,依靠第二个参数可更加精准的进行解绑。

语法 : xj.storage.localStorage.off(key[, callback])
    key : Required | String | 将要被解绑的目标 key 字符串
    callback : Optional | Function | 有传入该参数则该参数也对得上才会解绑


跨标签响应的 Storage 事件

下面这段代码同时存在于 demo_01_localStorage_testEvent.htmldemo_02_localStorage_testEvent.html 这两个页面,同时打开它们并点击按钮,就能看到 Storage 事件的跨标签响应了,两个页面的信息会自动同步,需要注意,点击 off 按钮解绑事件后,该页面就不会再响应 Storage 事件了,但其他页面会继续响应,也就是说事件虽然可以跨标签响应,但绑定和解绑还是需要逐个页面操作。


xj.storage.sessionStorage

xj.storage.sessionStorage 的属性和方法跟 xj.storage.localStorage 完全相同,所以这里就不重复了,但它们的 Storage 事件有些区别(原本就有区别,和 xj.storage 没关系),具体来讲就是 localStorage 的事件会在同源的其他页面里触发,包括其他标签页面和 iframe 框架页面,但 sessionStorage 的事件只会在同一个页面里的同源 iframe 框架页面中触发,无法跨标签响应。

下面这段代码同时存在于 demo_04_sessionStorage_testEvent.htmldemo_05_sessionStorage_testEvent.html 这两个页面,同时打开它们并点击按钮,可以发现同一个页面里的同源 iframe 页面会同步响应数据变化,但另一个标签页面则不会同步数据的变化,下面这段代码和上面那段代码是完全相同的,只是 localStorage 被改成了 sessionStorage,简写也从 xjls 变化为 xjss 而已。


全局配置

全局配置对 xj.storage.localStorage 对象和 xj.storage.sessionStorage 对象都会生效,需要注意的是,全局配置得在引入插件前就设置好,否则插件加载并执行的时候找不到配置,就会认为配置不存在,并且版本号还要对得上,否则插件也不会理会的,例如本页面使用的插件是 0.2.2 的版本,在 xj.storageConfig 对象后面跟着的就是 ['0.2.2'],版本匹配是考虑到多版本并存而设计的。


项目备注

01. IE11 在存入大额数据时,会出现不响应 Storage 事件的 BUG,这个大额数据的具体额度,在不同设备环境中不尽相同,详情可参考 IE11 doesn't fire local storage events when value is too large,XJ 曾尝试参考前面这个页面的说法,使用代理键值对的做法来解决这问题,但后来发现这种做法虽然能让 Storage 事件响应,但也会导致无法获取到准确的 newValue 属性,所以最后并没采用该方案,这问题也就没能解决,除非你并不需要兼容 IE11,否则在保存大额数据时,要记得这个数据可能不会引发 Storage 事件。

02. IE 和 Safari(MacOS) 的 Storage 事件会在操作数据的页面也触发,这是不标准的,为了能够判断该事件是否由当前页引发,所以 xj.storage 为每个页面都创建了 id,并在操作数据时将 id 也进行了保存,之后在响应 Storage 事件时再借助 id 进行判断,问题就得到了解决,但由于数据带上了 id,所以字节数会变多,使用 byte() 方法时会得到一个比预想中更大的值,就是这个原因了。

03. IE 存在着操作异步的问题,由于它会在数据还未正式写入文件时就执行回调,所以在 Storage 事件回调中使用 get() 方法获取值,可能得到的是触发事件前的旧值,但是你可以用 event 对象的 newValue 属性来获取新结果值,这属性的返回值总是对的。

04. 有疑问或者发现 BUG,可到 GitHub 提 Issue,如果觉得插件写得还行,在 GitHub 中为本项目点个 ★Star 吧,感谢啦 ಠ‿ಠ ❤。


推荐阅读

XJ.Chen - 漫谈 WebStorage API 既本地存储的 8 个 Feature 以及 20 个 BUG


Copyright © 2015- XJ.Chen All Rights Reserved
More XJ Plugins : https://github.com/xjZone/