关于浏览器:JavaScript重写LocalStorage方法实现浏览器本地存储设置时间问题

33次阅读

共计 4436 个字符,预计需要花费 12 分钟才能阅读完成。

最近遇到了用户登录信息本地存储的问题,所以须要对浏览器的 localStorage 的存储工夫进行设置,因而重写 localStorage 办法并在此记录。

浏览器几个存储总结:

  1. localStorage 保留的数据(大小 5M 左右),以“键值对”的模式长期存在。也就是说,每一项数据都有一个键名和对应的值,所有的数据都是以文本格式保留。保留的数据没有过期工夫,直到手动去除。
  2. sessionStorage 保留的数据(大小 5M 左右)用于浏览器的一次会话,当会话完结(通常是敞开窗口或标签页),数据被清空。
    sessionStorage 与 localStrage 和 Cookie 不同的一点在于,即使是雷同域名下的两个页面,只有它们不在同一个浏览器窗口中关上,那么它们的 sessionStorage 内容便无奈共享;
  3. cookie 以“键值对”的模式存在,是一些数据,存储于你电脑上的文本文件中。

总结 cookie、localStorage、sessionStorage 异同点比照

相同点:

  • 都是保留在浏览器端,且都是字符串类型的键值对。
  • 都遵循同源策略:当一个浏览器的两个 tab 页中别离关上来 百度和谷歌的页面
    当浏览器的百度 tab 页执行一个脚本的时候会查看这个脚本是属于哪个页面的,
    即查看是否同源,只有和百度同源的脚本才会被执行。

不同点:

  • 传递形式不同
  1. cookie 数据始终在同源的 http 申请中携带(即便不须要),即 cookie 在浏览器和服务器间来回传递。
  2. sessionStorage 和 loaclStorage 不会主动把数据发给服务器,仅在本地保留。
  • 数据大小不同
  1. cookie 数据还有门路(path)的概念,能够限度 cookie 只属于某个门路下。存储大小限度也不同,cookie 数据不能超过 4KB,同时因为每次 http 申请都会携带 cookie,所以 cookie 只适宜保留很小的数据,如会话标识。
  2. sessionStorage 和 localStorage 尽管也有存储大小的限度,但比 cookie 大得多,能够达到 5M 或者更大。
  • 数据有效期不同
  1. cookie:只在设置 cookie 过期工夫之前始终无效,即便窗口或浏览器敞开;
    localStorage:始终无效,窗口或浏览器敞开也始终保留,除非手动删除,因而用作持久数据;
    sessionStorage:仅在以后浏览器窗口敞开前无效,天然也就不可能长久放弃。
  • 作用域不同
  1. cookie:在所有同源窗口中都是共享的;
    localStorage:在所有同源窗口中也都是共享的;
    sessionStorage:不在不同的浏览器窗口中共享,即便是同一个页面。

因为 cookie 在 http 申请中每次都会被携带,生命周期只继续到浏览器敞开,而咱们须要让用户信息存储 24 小时,因而抉择手动封装 LocalStorage 办法。

  • setItem()实现思路及代码
    首先,changeHourToMs()办法:用于判断调用 setItem 办法时如果传入了小时,将其转化为毫秒,因为获取以后工夫时是毫秒级工夫。同时对于为传入 expires 或传入 expires 非法状况进行拦挡。
    而后,调用 Object.assign()办法:将初始化的数据与传入的数组合并,更新传入的数据。
    其次,判断 options.expires 办法是确定 options.expires 属性存在时,须要将整个对象的数据进行格局转换存入。
    否则,如果 options.expires 属性不存在,则意味着没有工夫限度,只需存储其 name 和 Value,而不关注存储的工夫和时常,存入即可。
  setItem(params) {
    const changeToMs = 60 * 60 * 1000;

    function changeHourToMs(params) {if (!Object.prototype.hasOwnProperty.call(params, "expires")) {return;}
      if (!isNumber(params.expires)) {console.log("expires 属性输出有误,应输出数字!")
        return;
      }
      params.expires = parseFloat(params.expires) * changeToMs;
    }

    const obj = {
      name: '',
      value: '',
      expires: 24 * 60 * 60 * 1000,
      startTime: new Date().getTime()// 存入缓存的工夫
    }
    const options = {};
    changeHourToMs(params);
    // 将 obj 和传进来的 params 合并(首先与 Obj 合并指定必要变量,而后与输出的 params 合并,如果 key 存在则增加 value,否则增加 key 和 value)
    Object.assign(options, obj, params);
    if (options.expires) {// 如果 options.expires 设置了的话,以 options.name 为 key,options 为值放进去
      localStorage.setItem(options.name, JSON.stringify(options));
    } else {
      // 如果 options.expires 没有设置,就判断一下 value 的类型
      const type = Object.prototype.toString.call(options.value);
      // 如果 value 是对象或者数组对象的类型,就先用 JSON.stringify 转一下,再存进去
      if (type === '[object Object]') {options.value = JSON.stringify(options.value);// 转换为 JSON 字符串
      }
      if (type === '[object Array]') {options.value = JSON.stringify(options.value);
      }
      localStorage.setItem(options.name, options.value);
    }
  }
  • getItem()实现思路及代码
    首先通过 name 取到数据,并将数据尝试进行 Json 格局的转换。
    而后确保数据非 null,判断是否传入了 options.expires 属性,如有进行下一步操作,否则将值返回。
    下一步操作:获取以后工夫做差,判断若超时间接清空缓存,并采纳阻塞提醒,用户信息生效,请从新登录,点击确定后跳转到登陆页面。

附:残缺代码如下;

import {isNumber} from "lodash";
import router from "umi/router";
import {Modal} from 'antd';

export default class Storage {constructor(name) {this.name = 'storage';}

// 应用阐明: 该类应用须要先初始化一个对象。// setItem 必须传入的值为:name,vlaue.
// expires 为限度工夫默认为一天,如有须要可传入存储的工夫(以小时为单位)// startTime 默认获取以后工夫,无需传入
  setItem(params) {
    const changeToMs = 60 * 60 * 1000;

    function changeHourToMs(params) {if (!Object.prototype.hasOwnProperty.call(params, "expires")) {return;}
      if (!isNumber(params.expires)) {console.log("expires 属性输出有误,应输出数字!")
        return;
      }
      params.expires = parseFloat(params.expires) * changeToMs;
    }

    const obj = {
      name: '',
      value: '',
      expires: 24 * 60 * 60 * 1000,
      startTime: new Date().getTime()// 存入缓存的工夫
    }
    const options = {};
    changeHourToMs(params);
    // 将 obj 和传进来的 params 合并(首先与 Obj 合并指定必要变量,而后与输出的 params 合并,如果 key 存在则增加 value,否则增加 key 和 value)
    Object.assign(options, obj, params);
    if (options.expires) {// 如果 options.expires 设置了的话,以 options.name 为 key,options 为值放进去
      localStorage.setItem(options.name, JSON.stringify(options));
    } else {
      // 如果 options.expires 没有设置,就判断一下 value 的类型
      const type = Object.prototype.toString.call(options.value);
      // 如果 value 是对象或者数组对象的类型,就先用 JSON.stringify 转一下,再存进去
      if (type === '[object Object]') {options.value = JSON.stringify(options.value);// 转换为 JSON 字符串
      }
      if (type === '[object Array]') {options.value = JSON.stringify(options.value);
      }
      localStorage.setItem(options.name, options.value);
    }
  }

  // 拿到缓存
  getItem(name) {let item = localStorage.getItem(name);
    try {    // 先将拿到的试着进行 json 转为对象的模式,不能够的话间接返回字符串
      item = JSON.parse(item);
    } catch (error) {console.log(error);
      item = item;
    }
    if (item !== null) {if (item.startTime) {    // 如果有 startTime 的值,阐明设置了生效工夫
        const date = new Date().getTime();
        if (date - item.startTime > item.expires) {// 判断是否超时
          localStorage.removeItem(name);// 革除超时缓存
          Modal.warning({
            content: '用户受权已生效,请从新登录!',
            onOk() {router.push("/user/login");
            },
          });
          return null;
        }
        return item.value;        // 缓存未过期,返回值

      }
    }
    return item;    // 如果没有设置生效工夫,间接返回值

  }

  removeItem(name) {localStorage.removeItem(name);
  }

  clear() {localStorage.clear();
  }
}

正文完
 0