uniapp运行在app端如何使用缓存

uniapp运行在app端如何使用缓存

​ 众所周知,uniapp 可以一套代码,多端运行。但是需要注意的是,window 对象以及document 是浏览器特有的(所以app端无法使用localStorage 等api),因此,uniapp 贴心的为我们准备了getStorage 以及setStorage 等操作缓存的api。除此以外,还有vue 官方推荐的pinia也可以操作缓存。那么当这两者同时存在于一个项目时,我们应该是他们完美结合起来呢?

为什么uniapp提供了所需的api之后还要用到pinia呢?

​ 有这么一个场景:在程序启动时我需要轮询服务器接口获取是否新数据的产生,如果有,则将hasRead字段设为true,又因为这个hasRead字段我需要在程序启动时就能拿到值,因此我是用setStorageapi将其写进缓存。那么,问题来了,我如何将缓存的字段变为响应式的呢?为什么需要响应式?因为当有新数据产生时,我需要在界面中提示用户,而这个字段我是设置在缓存当中的。最开始我是用了以下2种方式来达到响应式的结果。

js 复制代码
// 第一种
const cache = uni.getStorageSync('hasRead')
const hasRead = ref(cache)

watch(() => hasRead.value, (newval) => {
	if (newval) {
		hasRead.value = newval
	}
})

// 第二种
const hasRead = ref(true)
const hasReadCache = computed(() => {
	const cache = uni.getStorageSync('hasRead')
	if (cache) {
		return cache
	}
	return hasRead.value
})

答案显而易见,以上2种方案都无法使缓存变化的同时响应到页面当中(有小伙伴知道原因的话,评论区留言告诉我一下为什么不可以),于是,我秉着试一试的想法使用了pinia以及pinia-plugin-persistedstate

js 复制代码
import { defineStore } from 'pinia'
import { ref } from 'vue'
export const useSettingStore = defineStore('setting', () => {
    const hasRead = ref(true)
    const setHasRead = (value) => {
        hasRead.value = value
    }
}, {
    persist: {
        storage: localStorage,
        pick: ['hasRead']
    }
})

通过pinia,我成功实现的数据的响应式,并且能够将数据存于缓存。那么,问题解决了吗?并没有。为什么呢?因为程序最终时需要运行在Android 以及IOS 环境的,而以上环境并没有window 对象,因此也不会有localStorage 。那么应该怎么办呢?机缘巧合之下,当我鼠标移入persist中的storage对象时,编辑器跳出来他的类型为StorageLike ,直译一下就是像Storage,那么是不是可以理解为我声明一个Storage对象,只要具有像localStorage对象的api也可以呢?刚好uniapp也提供了类似的api,说干就干,我创建了一个类,如下:

js 复制代码
// utils/storage.js

class Storage {
  /**
   * 设置缓存
   * @param {string} key 缓存键
   * @param {any} value 缓存值
   * @param {number} [expire] 过期时间(单位:秒)
   * @returns {boolean} 是否设置成功
   */
  setItem(key, value, expire) {
    try {
      const data = {
        value,
        // 计算过期时间戳(如果设置了过期时间)
        expireTime: expire ? Date.now() + expire * 1000 : null,
      };
      uni.setStorageSync(key, data);
      return true;
    } catch (e) {
      console.error('Storage setItem error:', e);
      return false;
    }
  }

  /**
   * 获取缓存(自动处理过期数据)
   * @param {string} key 缓存键
   * @returns {any|null} 缓存值或null
   */
  getItem(key) {
    try {
      const data = uni.getStorageSync(key);
      if (!data) return null;

      // 检查是否过期
      if (data.expireTime && Date.now() > data.expireTime) {
        this.removeItem(key);
        return null;
      }
      return data.value;
    } catch (e) {
      console.error('Storage getItem error:', e);
      return null;
    }
  }

  /**
   * 删除指定缓存
   * @param {string} key 缓存键
   */
  removeItem(key) {
    try {
      uni.removeStorageSync(key);
    } catch (e) {
      console.error('Storage removeItem error:', e);
    }
  }

  /**
   * 清空所有缓存
   */
  clear() {
    try {
      uni.clearStorageSync();
    } catch (e) {
      console.error('Storage clear error:', e);
    }
  }

  /**
   * 检查缓存是否存在
   * @param {string} key 缓存键
   * @returns {boolean}
   */
  has(key) {
    return this.keys().includes(key);
  }

  /**
   * 获取所有缓存键
   * @returns {string[]}
   */
  keys() {
    try {
      const { keys } = uni.getStorageInfoSync();
      return keys;
    } catch (e) {
      console.error('Storage keys error:', e);
      return [];
    }
  }

  /**
   * 获取缓存信息
   * @returns {{
   *   keys: string[],
   *   currentSize: number,
   *   limitSize: number
   * }}
   */
  getInfo() {
    try {
      return uni.getStorageInfoSync();
    } catch (e) {
      console.error('Storage getInfo error:', e);
      return { keys: [], currentSize: 0, limitSize: 0 };
    }
  }

  /**
   * 设置缓存过期时间
   * @param {string} key 缓存键
   * @param {number} expire 过期时间(单位:秒)
   * @returns {boolean}
   */
  setExpire(key, expire) {
    const value = this.getItem(key);
    if (value === null) return false;
    return this.setItem(key, value, expire);
  }

  /**
   * 检查并清理所有过期缓存
   */
  checkExpire() {
    this.keys().forEach((key) => {
      // 通过getItem自动触发过期检查
      this.getItem(key);
    });
  }
}

// 创建单例实例
export const storage = new Storage();

利用storage 对象,我将store变成以下代码:

js 复制代码
import { defineStore } from 'pinia'
import { ref } from 'vue'
import { storage } from '@utils'
export const useSettingStore = defineStore('setting', () => {
    const hasRead = ref(true)
    const setHasRead = (value) => {
        hasRead.value = value
    }
}, {
    persist: {
        storage: {
            getItem: (key) => storage.getItem(key),
            setItem: (key, value) => storage.setItem(key, value),
            removeItem: (key) => storage.removeItem(key),
          },
        pick: ['hasRead']
    }
})

通过以上思路,我成功解决了uniapp的storagepinia的结合,并解决了缓存的响应式问题。

最后,虽然这个轮询的方案被我废弃了,但是我还是从其中学到了之前我从未接触到的东西。还有就是如果小伙伴学到了的话,也请点赞,关注。感谢您的支持!!

相关推荐
西洼工作室7 小时前
unipp+vue3+python h5+app极验验证码集成全流程解析
前端·uni-app·全栈·极验
RuoyiOffice16 小时前
SpringBoot+Vue3 实现 OA 公文外来文与归档台账:外部收文、BPM办理、三类公文统一归档
spring boot·微服务·uni-app·vue·ruoyi·anti-design-vue·ruoyioffice
云起SAAS2 天前
私域直播系统UniApp源码 多商户商城+直播带货 微信小程序+H5+安卓iOS
android·微信小程序·uni-app·私域直播系统
专科3年的修炼3 天前
uni-app移动应用开发第四章
开发语言·javascript·uni-app
q5507071774 天前
uniapp/uniappx实现原生图片编辑涂鸦、贴图、滤镜、旋转、裁剪等
uni-app
计算机学姐5 天前
基于微信小程序的校园失物招领管理系统【uniapp+springboot+vue】
java·vue.js·spring boot·mysql·信息可视化·微信小程序·uni-app
2501_915921435 天前
HTTPS前端劫持 新一代流量劫持解决方案
前端·网络协议·ios·小程序·https·uni-app·iphone
爱怪笑的小杰杰5 天前
优化 UniApp 日历组件的多语言切换:告别 setLocale 引起的 App 重启
java·前端·uni-app
计算机学姐5 天前
基于微信小程序的宠物服务系统【uniapp+springboot+vue】
java·vue.js·spring boot·mysql·微信小程序·uni-app·宠物
2501_915909065 天前
iOS应用签名的三种方法全解析:从官方到第三方工具
android·ios·小程序·https·uni-app·iphone·webview