localStorage和sessionStorage

264 阅读2分钟

一、localStorage与sessionStorage的比较

1、不同点:

1-1、localStorage

没有过期时间设置,可以长期保留

相同浏览器的不同窗口,数据可以共享

限制大小为5M

1-2、sessionStorage

关闭浏览器或窗口,数据会被清除

相同浏览器的相同的URL的多个窗口,数据相互隔离

在浏览器打开期间一直保持,并且重新加载或恢复页面仍会保持原来的数据

通过window.open或链接打开新页面时,新页面能获取上一个页面的数据

2、相同点:

不同浏览器之间的数据相互隔离

不同协议(http与https)+主机名+端口之间的数据相互隔离

无痕/安全模式下启动浏览器和正常启动浏览器之间的数据相互隔离

二、localStorage与sessionStorage的封装

import aes from 'crypto-js/aes';
import utf8Enc from 'crypto-js/enc-utf8';

const PREFIX = '___cache__';

//GUID:全球唯一标识符
function guid() {
  return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {
    const r = Math.random() * 16 | 0;
    const v = c == 'x' ? r : (r & 0x3 | 0x8);
    return v.toString(16);
  });
}

function getSid() {
  const sid = localStorage.getItem('__sid');
  if (sid) return sid;
  const id = guid();
  localStorage.setItem('__sid', id);
  return id;
}

function removeSid() {
  localStorage.removeItem('__sid');
}

function _Store(store: Storage) {
  return class S {

    //生成加密需要的key和iv
    private static getKV() {
      const id = getSid();
      const s = id.replace(/-/g, '').split('').reverse().join('');
      return { key: s.substring(0, 16), iv: s.substring(16, id.length) }
    }

    //加密(crypto-js库加密)--如果是非生产环境,不加密
    private static encrypt(data: string) {
      if (process.env.NODE_ENV !== 'production') return data;
      const { key, iv } = this.getKV();
      //加密
      return aes.encrypt(utf8Enc.parse(data), key, { iv: iv as any }).toString();
    }

    //解密--如果是非生产环境,不加密
    private static decrypt(data: string) {
      if (process.env.NODE_ENV !== 'production') return data;
      try {
        const { key, iv } = this.getKV();
        //解密
        const rs = aes.decrypt(data, key, { iv: iv as any });
        return utf8Enc.stringify(rs);
      } catch (e) {
        return null
      }
    }

    private static encryptKey(key: string) {
      return `${PREFIX}${key}`;
    }

    public static getItem(k: string) {
      try {
        const key = this.encryptKey(k);
        const value = this.decrypt(store.getItem(key) as string) ;
        return JSON.parse(value as string).data;
      } catch (e) {
        return null;
      }
    }

    public static getDefaultValue<T>(k: string, value: T): T {
      const v = S.getItem(k);
      return v === null ? value : v;
    }

    public static setItem<T>(k: string, v: T) {
      const key = this.encryptKey(k);
      const d = JSON.stringify({ data: v });
      store.setItem(key, this.encrypt(d));
    }

    public static removeItem(k: string) {
      const key = this.encryptKey(k);
      store.removeItem(key);
    }

    public static clear() {
      Object.keys(store).filter((i: string) => i.startsWith(PREFIX)).forEach((j) => store.removeItem(j));
      removeSid();
    }
  };
}

export const CacheStore = _Store(localStorage);
export const CacheSession = _Store(sessionStorage);

三、浏览器多个tab页中共享sessionStorage

实现思路:监听storage事件,把值放在localStorage中传递,一定要调用removeItem清除

参考:

在浏览器的多个tab页中共享sessionStorage

四、跨浏览器tab页通信

实现思路:HTML5的window.postMessage和监听storage事件来实现

参考:

跨浏览器tab页的通信解决方案尝试

五、注意

localStorage或者sessionStorage的值发生变化时,storage事件才会触发。如果是相同的值,storage事件不会触发

storage事件只能在不同的tab页能监听到,在同一个tab页监听事件不会触发,例如:tab的A页面localStorage或者sessionStorage的值发生变化,在另一个tab的B页面才会触发storage事件