前端本地存储localStorage及应用
localStorage是HTML5定义的一种本地存储方式,其特点是可以长期存储在用户本地磁盘且容量较大,w3c标准建议的代理端容量是 5MB,前端可以将一些Server不需要的数据保存在localStorage而非cookie中。
window.localStorage
localStorage是Storage对象的实例,我们可以看看Storage都有哪些方法:
var c = Object.getOwnPropertyNames(Storage)
for (var d of c) {
var e = Object.getOwnPropertyDescriptor(Storage, d)
if ((e.value !== null && typeof e.value === 'object') || (typeof e.value === 'function')) {
console.log(d, e.value);
}
if (e.get) {
console.log(d, 'get', e.get);
}
if (e.set) {
console.log(d, 'set', e.set);
}
}
在我的Chrome浏览器运行的结果是:
可见Storage的原型上包含clear, getItem, setItem, removeItem, key这几个方法,还有一个类似Array对象的length属性,表明其包含多少条存储信息。
根据MDN文档,Storage中的键值对总是以字符串的形式存储,各方法的描述如下:
API | 说明 |
---|---|
Storage.key() | 接受一个数值 n 作为参数,并返回存储中的第 n 个键名。 |
Storage.getItem() | 接受一个键名作为参数,返回键名对应的值。 |
Storage.setItem() | 接受一个键名和值作为参数,将会把键值对添加到存储中,如果键名存在,则更新其对应的值。 |
Storage.removeItem() | 接受一个键名作为参数,并把该键名从存储中删除。 |
Storage.clear() | 调用该方法会清空存储中的所有键名。 |
结合具体业务应用
在实际业务中,我们需要在本地存储一些不经常变更的信息,比如图片链接这种;另外,由于localStorage没有自动过期的设定,需要通过js操作,我们设置一个额外的键管理过期时间(本文中为cache_expire), 具体如下图所示:
基本的代码实现如下:
!function (w) {
var expire = "cache_expire"; // 管理过期的键
var last = 3e9; // 过期时间
w.Cache = Cache = function (data) {
if (! (this instanceof Cache)) {
return new Cache(data);
}
this.obj = null;
try {
data instanceof Object && (this.obj = data);
} catch (e) {
this.obj = null;
}
}
Cache.prototype.getItem = function (key) {
return this.obj && this.obj.hasOwnProperty(key) ? this.obj[key] : '';
}
Cache.prototype.setItem = function (key, value) {
this.obj || (this.obj = {});
this.obj[key] = value;
}
Cache.prototype.removeItem = function (key) {
if (this.hasOwnProperty('obj')) {
try {
delete this.obj[key];
} catch (e) {
this.obj[key] = null;
}
}
}
Cache.prototype.hasData = function () {
if (! this.obj) {
return false;
}
// this.obj 需要为对象
for (var o in this.obj) {
return true;
}
return false;
}
Cache.get = function (key) {
if (w.localStorage) return new Cache(null);
try {
var remList = JSON.stringify(w.localStorage.getItem(expire) || "{}");
// 检测是否过期,过期则返回一个空Cache对象
return remList[key] > (new Date).getTime() ? new Cache(JSON.parse(w.localStorage.getItem(key))) : new Cache(null);
} catch (e) {
return new Cache(null);
}
}
Cache.set = function (key, value) {
if (w.localStorage) {
if (! value instanceof Cache) {
console.log('value should be as Cache Object');
return false;
}
// 每次更改重置过期时间
var list = JSON.parse(w.localStorage.getItem(expire)) || {};
list[key] = (new Date).getTime() + last;
try {
w.localStorage.setItem(expire, JSON.stringify(list));
w.localStorage.setItem(key, JSON.stringify(value.obj));
} catch (e) {
}
}
}
Cache.clear = function (key) {
if (w.localStorage) {
var list = JSON.parse(w.localStorage.getItem(expire)) || {};
try {
list[key] && delete list[key];
w.localStorage.setItem(expire, JSON.stringify(list));
w.localStorage.removeItem(key);
} catch (e) {
}
}
}
// 打开页面后检测本地存储是否过期
setTimeout(function () {
var list = JSON.parse(w.localStorage.getItem(expire)) || {};
var current = (new Date).getTime();
for (var i in list) {
list[i] < current && Cache.clear(i);
}
}, 5e3)
}(window)
在实际应用中包装一层即可:
function editCache (key, value) {
if (window.Cache) {
var cacheKey = key;
var cacheObj = Cache.get(cacheKey);
var cacheData = {};
if (cacheObj.hasData()) {
cacheData = cacheObj.getItem('data');
}
// 更改内容
cacheData[key] = value;
cacheObj.setItem('data', cacheData);
Cache.set(cacheKey, cacheObj);
}
}
editCache('user_info', {
name: 'Jack',
profiles: ['a.jpg', 'b.jpg', 'c.jpg']
})
editCache('user_imglist', {
url: []
})