前言

这次的问题来源于一个简单的需求,要给某个勾选框加上一个月的缓存有效期,即只要选中了这个勾选框,在接下来的一个月内再次进来都会默认勾选上。

什么?这么简单,用缓存记录一下是否勾选的字段,在用缓存存一下当前的时间或者过期的时间,进来的时候判断有没有到时间不就好了吗?

对的,没错,就是这么简单。但是今天做的事就是把这个做成通用一点,你想,假如我们有很多的缓存都想加个有效期,那不可能每一个缓存都去单独给他去另外存一个时间吧,这个有点麻烦,而且有占空间。所以,我们能不能直接在设置缓存的时候就给他加个有效期的参数呢,这样就简单多了

思路

我的项目是用uniapp搭建的,所有要改写的api是uni.setStorageSyncuni.getStorageSync。用原生小程序也是一样的,没什么差别。

首先,先想想看我们希望怎么用最方便,是不是直接在uni.setStorageSync的最后面补一个时间最方便啊,像这样

uni.setStorageSync('test1', 123, 5000) // 使用相对时间
uni.setStorageSync('test2', 123, '2021/8/1') // 使用绝对时间

实现思路很简单:

在存储缓存的时候,把后面的时间也一并存起来,在读取的时候先比对当前时间与存储的时间,如果过期了,则清空缓存并返回空,没过期则正常返回

那么时间该存在哪呢?

我们可以存储一个对象,对象包含一个expires属性和一个data属性,然后再改写geStorageSync,取值的时候去data里面的值

uni.setStorageSync('test1', 123, 5000)//
//实际存储在缓存中为:{ expires: 5000, data: '123'}

实现

知道原理后代码就很简单了

// 导出后再main.js中引入调用即可
export function uniStorage() {
  // 存
  const originSetStorageSync = uni.setStorageSync
  uni.setStorageSync = function(key, data, expires) {
      // 如果没有传第三个有效期参数,就还是用原来的方法
    if (!expires) return originSetStorageSync(key, data)

    const reg = /\d{4}\/\d{1,12}\/\d{1,31}/ // 这个正则写的比较偷懒,是不够准确的哈哈。用来验证绝对时间格式`yyyy/MM/dd`或者`yyyy/MM/dd hh:mm:ss`
    if (reg.test(expires)) { // 绝对日期
      const timestamp = new Date(expires + '').getTime()
      
      if (isNaN(timestamp)) {
        console.error(expires + ' error 请传入正确的日期格式:yyyy/MM/dd 或者 yyyy/MM/dd hh:mm:ss')
        return originSetStorageSync(key, data)
      }
      originSetStorageSync(key, { data, expires: timestamp })
    } else {// 相对日期
      if (typeof expires !== 'number') {
        console.error('expires is not a number')
        return originSetStorageSync(key, data)
      }
      originSetStorageSync(key, { data, expires: +new Date() + expires })
    }
  }

  // 取
  const originGetStorageSymc = uni.getStorageSync
  uni.getStorageSync = function(key) {
    const data = originGetStorageSymc(key)
    // 如果data不是个对象就说明是没加有效期的,直接返回
    if (typeof data !== 'object' || (typeof data === 'object' && !data.expires)) return data

    const now = +new Date()
    if (now < data.expires) {//用当前时间和存储的时间对比
      return data.data // 未过期返回data
    } else {
        // 已过期,移除缓存,返回空
      uni.removeStorageSync(key)
      return ''
    }
  }
}

测试使用

uni.setStorageSync('test', 123) //原使用方式,不加有效期
uni.setStorageSync('test1', 123, 5000) // 使用相对时间
uni.setStorageSync('test2', 123, '2021/7/10') // 使用绝对时间

setTimeout(() => {
    console.log(uni.getStorageSync('test1')) // 123
}, 3000)
setTimeout(() => {
    console.log(uni.getStorageSync('test1')) // ''  --已过期
}, 6000)

总结

  • 扩写uni.setStorageSyncapi,使其支持第三个参数,绝对时间或者相对时间
  • 判断传入的时间是相对还是绝对,再统一转为时间戳,存储一个在对象上,如:{expires: 1627385915263, data:test}
  • 改写uni.geetStorageSync,取值的时候判断类型是否为对象,是的话再比对当前时间与存储的时间,如果大于存储时间则已过期,情况缓存并返回空,未过期则返回对象的data值

完事~