js-cookie工具库

942 阅读3分钟

1. 原生cookie使用

获取cookie(当前位置可访问的)

let allCookie = document.cookie

设置cookie

// 给document.cookie传入一个键值对形式的字符串
document.cookie="name=xxx;" 

额外属性

  • ;path=path 默认为当前文档位置的路径。(例如 '/', '/mydir'),
  • ;domain=domain 默认为当前文档位置的域名。(例如 xxx.com)
  • ;max-age=max-age-in-seconds 从文档被访问开始的cookie的存活时间/秒
  • ;expires=date-in-GMTString-format 过期时间 注意其格式Wed, 14 Jun 2017 07:00:00 GMT
  • ;secure ture/false 如果为true则只通过 https 协议传输

注意:如果max-age和expires同时存在 max-age生效,如果两个都不存在那么当前cookie在当前会话时间内生效

MDN官方

2. 使用js-cookie库

Cookies.set('name', 'value', { expires: 7, path: '' })

Cookies.get('name') // => 'value'
Cookies.get('nothing') // => undefined

Cookies.remove('name')

...

参考npmjs中js-cookie

js-cookie源码拉下来 src/api.mjs src/assign.mjs src/converter.mjs

  • 这里有一个.mjs 结尾的文件,表示文件使用es模块 还有一个.cjs结尾的文件,表示文件使用commonjs模块....

主要关注src/api.mjs 可以看到有三个方法 set、get、remove;这就是核心

set方法
  function set (name, value, attributes) {
    if (typeof document === 'undefined') {
      return
    }

    // 整合传进来的参数 如果属性名相同则覆盖default
    attributes = assign({}, defaultAttributes, attributes)
    // attributes = {path: '/'}

    // 传入的时间 转化成时间戳
    if (typeof attributes.expires === 'number') {
      attributes.expires = new Date(Date.now() + attributes.expires * 864e5)
    }
    // 时间戳转化成 Wed, 14 Jun 2017 07:00:00 GMT 这种格式的数据
    if (attributes.expires) {
      attributes.expires = attributes.expires.toUTCString()
    }

    // 这边我没有过度关注 只知道他是一个编码过程
    name = encodeURIComponent(name)
      .replace(/%(2[346B]|5E|60|7C)/g, decodeURIComponent)
      .replace(/[()]/g, escape)

    var stringifiedAttributes = ''
    for (var attributeName in attributes) {
      if (!attributes[attributeName]) {
        continue
      }

      stringifiedAttributes += '; ' + attributeName

      if (attributes[attributeName] === true) {
        continue
      }

      // Considers RFC 6265 section 5.2:
      // ...
      // 3.  If the remaining unparsed-attributes contains a %x3B (";")
      //     character:
      // Consume the characters of the unparsed-attributes up to,
      // not including, the first %x3B (";") character.
      // ...
      
      // ;path=/ ...
      stringifiedAttributes += '=' + attributes[attributeName].split(';')[0]
    }

    // 这边set了cookie 并且返回了它
    return (document.cookie =
      name + '=' + converter.write(value, name) + stringifiedAttributes)
  }
get方法
  function get (name) {
    if (typeof document === 'undefined' || (arguments.length && !name)) {
      return
    }

    // To prevent the for loop in the first place assign an empty array
    // in case there are no cookies at all.
    // yong; 分割字符串 返回数组
    // 例: name=xx=123; age=12 => [name=xx,age=12]
    var cookies = document.cookie ? document.cookie.split('; ') : []
    
    // 创建一个空对象来存储最后的结果
    var jar = {}
    for (var i = 0; i < cookies.length; i++) {
      var parts = cookies[i].split('=') // parts [name, xx]
      var value = parts.slice(1).join('=') // xx 
      // 这一步还有一个作用 如果value中有=号 比如 name=xxx=123 那么parts就是[name,xxx,123] 这边就会把xxx和123结合起来 =》 value为xxx=123

      try {
        // 对parts[0]decode
        var found = decodeURIComponent(parts[0])
        // 组成对象 =》 {name:xxx=123}
        jar[found] = converter.read(value, found)

        // 如果name === found 也就是找到了传入name对应的value
        if (name === found) {
          break
        }
      } catch (e) {}
    }

    // 找到了就返回jar[name] 没有就返回空对象
    return name ? jar[name] : jar
  }
remove方法

remove() 方法就是把对应name的expires属性设置为过期时间

      remove: function (name, attributes) {
        set(
          name,
          '',
          assign({}, attributes, {
            expires: -1
          })
        )
      },
withAttributes 方法
      withAttributes: function (attributes) {
        return init(this.converter, assign({}, this.attributes, attributes))
      },

assign({}, this.attributes, attributes) 整合了一下attributes,然后调用init方法 这里为啥要调用init方法呢 如果调用init方法创建一个实例 那么自定义的参数就会影响所有的已经存在的实例!这样不被允许。所有调用init方法创建了一个新的实例 不会影响别人

withConverter 方法同理

attributes、converter
    {
      attributes: { value: Object.freeze(defaultAttributes) },
      converter: { value: Object.freeze(converter) } // 这里把这两个对象冻结,防止被修改
    }

3. 简单实现

功能
  • set功能
  • get功能
  • del功能
  • 配置注册中心部分
  • 冻结配置
总结

用 init 函数创建对象,对象里有以下函数

get 函数:将 document.cookie 字符串转化为 Object 形式,转化过程中判断是否在存 key,如果有就返回对应 value set 函数:把 attributes stringify,然后追加到 key=value 后, document.cookie = key={key}={value}${attrStr} del 函数:调用 set,把 expires 设置为 -1 天,cookie 直接过期被删除 withAttributes:更新 attributes 配置,并返回全新 Cookie 对象 withConverter:更新 converter 配置,并返回全新 Cookie 对象 为什么要用函数生成对象这么麻烦?因为要解决全局污染的问题。需要把 attributes 和 converter 两个配置存到函数参数里,并且通过 withAttributes 和 withConverter 调用 init 返回新 Cookie 对象。 为什么要冻动 attributes 和 converter。

我的实现:my-js-cookie