Cookie.js

/**
 * cookie管理器
 * 利用前端存储,模拟实现web中的cookie逻辑,详见{@tutorial 2.4-cookie}
 * 注:目前仅支持基础的取值赋值操作,domain、path、expires等各种配置选项暂未支持,会予以忽略
 */
class Cookie {
  _cookieStorage = ''; //cookie相关信息存储到storage时使用的key
  _cookieStr = ''; //当前cookie列表,格式:'key1=value1;key2=value2'

  /**
   * 构造函数
   * @param {string} [cookieStorageName='__cookie'] cookie相关信息存储到storage时使用的key
   */
  constructor({cookieStorageName='__cookie'}={}){
    this._cookieStorage = cookieStorageName;
  }

  /**
   * 读取指定cookie
   * key未传时,返回全部cookie
   * @param {string} [key] 要读取的key
   * @param {object} [options] 配置选项(暂未支持)
   * @return {string | object} cookie中key对应的value | 未传key时,返回全部key-value组成的对象
   * @example
   * //假设当前环境所有cookie为:a=1;b=2;c=3
   * cookie.get('a'); //返回值:'1', cookie中存在指定key时,会返回其对应值
   * cookie.get('nonExist'); //返回值:'',  cookie中不存在指定key时,会返回空串
   * cookie.get(); //返回值:{a:'1', b:'2', c:'3'},未传key时,会返回全部key-value组成的对象
   */
  get(key, options){
    let cookieStr = this.getCookie();
    let cookieObj = Cookie.cookieStrToObj(cookieStr);
    return key === undefined ? cookieObj : (cookieObj[key] || '');
  }

  /**
   * 写入指定cookie
   * @param {string} key 要写入的key
   * @param {string} value 要写入的value
   * @param {object} [options] 配置选项(暂未支持)
   */
  set(key, value, options){
    this.setCookie(`${key}=${value};`);
  }

  /**
   * 获取当前可访问的cookie字符串
   * @return {string} cookie字符串,形如:'key1=value1;key2=value2'(类似web中读取document.cookie)
   */
  getCookie(){
    // 优先尝试从内存中读取,尽量减少访问storage的开销
    if(this._cookieStr)
      return this._cookieStr;
    
    this._cookieStr = wx.getStorageSync(this._cookieStorage);
    return this._cookieStr;
  }

  /**
   * 写入cookie
   * @param {string} setStr 写入指令,格式形如:'key1=value1; path=/;'(类似web中document.cookie赋值)
   */
  setCookie(setStr){
    //参数处理
    setStr = setStr.trim();
    
    //字段配置
    let setKey = ''; //要赋值的key
    let setValue = ''; //要赋值的value
    let configOptions = {}; //配置项:domain、path、expires等
    
    //字段解析
    let fieldStrArr = setStr.split(/\s*;\s*/);
    for (let [fieldIdx, fieldStr] of fieldStrArr.entries()) {
      let sepIdx = fieldStr.indexOf('=');
      let name = fieldStr.substring(0, sepIdx);
      let value = fieldStr.substring(sepIdx+1);
      
      if (fieldIdx === 0) { //第一个选项,认为是要赋值的key
        setKey = name;
        setValue = value;
      } else { //其它选项,认为是配置项
        configOptions[name.toLowerCase()] = value;
      }
    } 
    
    //字段检查
    if (!setKey) {
      console.error('[setCookie] bad param, no key found:', setStr);
      return;
    }
    
    //更新cookie(配置项暂予忽略)
    this._cookieStr = Cookie.mergeCookieStr(this._cookieStr, `${setKey}=${setValue};`);
    wx.setStorage({
      key: this._cookieStorage,
      data: this._cookieStr,
    });
  }

  /**
   * 将'key1=value1;key2=value2'形式的cookie字符串转为{key1: value1, key2: value2}的对象形式
   * @param {string} cookieStr
   * @return {Object} cookieObj
   */
  static cookieStrToObj(cookieStr){
    let fieldStrArr = cookieStr.split(/\s*;\s*/).filter(fieldStr=>!!fieldStr);
    let cookieObj = {};

    for (let fieldStr of fieldStrArr) {
      // 注意不要直接用匹配split('='), ppu等含=的不规则cookie会出错
      let index = fieldStr.indexOf('=');
      let key = fieldStr.substring(0, index);
      let value = fieldStr.substring(index+1);

      cookieObj[key] = value;
    }

    return cookieObj;
  }

  /**
   * 将{key1: value1, key2: value2}的对象形式键值对转为'key1=value1;key2=value2'形式的cookie字符串
   * @param {Object} cookieObj
   * @return {string} cookieStr
   */
  static cookieObjToStr(cookieObj){
    let cookieStr = '';
    for (let key in cookieObj)
      cookieStr += `${key}=${cookieObj[key]};`;
    return cookieStr;
  }

  /**
   * 将'key1=value1;key2=value2'形式的cookie字符串合并,key相同时后面的覆盖前面的
   * @param {...string} cookieStrs 待合并的cookie字符串
   * @return {string} 合并后的cookie字符串
   */
  static mergeCookieStr(...cookieStrs) {
    let cookieObjs = cookieStrs.filter(cookieStr=>!!cookieStr).map(Cookie.cookieStrToObj);

    let cookieObj = Object.assign(
      {},
      ...cookieObjs,
    );

    return Cookie.cookieObjToStr(cookieObj);
  }
}

export default Cookie;