weixin_58412143 2025-09-22 13:42 采纳率: 83.7%
浏览 8

vue,ts写微信公众号,用户信息缓存问题

在登录页调用了fetchCardInfo接口用于获取用户信息(内容很多有昵称头像钱包等等)然后在首页我的页等需要这个接口里的内容,
问题:那么在首页,我的页,需要再次判断是否有缓存内容吗?还是直接获取即可
首页--

// 使用计算属性从store中获取卡片信息,确保始终返回一个对象以避免undefined错误
const cardInfo = computed(() => {
  if (userStore.cardInfo && Object.keys(userStore.cardInfo).length > 0) {
    return userStore.cardInfo;
  }
  // 返回默认空对象,避免在模板中访问属性时出现undefined错误
  return {
    CardEndDate: '',
    CardSerNo: '',
    CardTypeName: '',
    balance: '0',
    EmployeeNo: '',
    CardAvailableCredit: 0.00,
    BagsInfo: [{
      BagsID: null,
      BagsType: '',
      BagsBalance: 0.00,
      BagsExpExpireTime: ''
    }]
  };
});

onMounted(() => {
  // console.log('home--- route.query.OpenID', route.query.OpenID);
  // 页面加载时,检查是否已缓存卡片信息,如果没有则获取
  if (!userStore.cardInfo || Object.keys(userStore.cardInfo).length === 0) {
    fetchCardInfoIfNeeded();
    console.log('home---获取卡片信息');
  }
});

// 获取卡片信息的函数
const fetchCardInfoIfNeeded = async () => {
  console.log('home---获取卡片信息的函数');
  try {
    await userStore.fetchCardInfo();
    console.log('home---获取卡片信息成功:', cardInfo.value.BagsInfo);
  } catch (error) {
    console.error('home---获取卡片信息失败:', error);
    // 可以在这里显示一个提示,告知用户无法获取最新信息
    // showToast('无法获取最新卡片信息,请稍后再试');
  }
};

我的页——

const cardInfo = computed(() => {
  if (userStore.cardInfo && Object.keys(userStore.cardInfo).length > 0) {
    return userStore.cardInfo;
  }
  // 返回包含所有必要属性的默认对象,避免在模板中显示空白
  return {
    EmployeeName: '',
    EmployeeNo: '',
    EmployeeStatusName: '',
  };
});

登录页-——

try {
        await userStore.fetchCardInfo();
        console.log('登录---卡片信息获取成功', userStore.cardInfo.BagsInfo);
      } 
//接口返回数据如——
  "CardTypeName": "学生卡",
    "CardAccountType": "贷记卡",
    "CardStatusName": "正常",
    "CardCredit": 1000,
    "CardCashBalance": 10,
    "CardSubsidyBalance": 0,
    "CardAvailableCredit": 1010,
    "CardEndDate": "2025-09-01T00:00:00",
    "CardBackImage": "http://192.168.80.222:6600/images/CardBack.jpg",
    "BagsInfo": [
      {
        "BagsID": 1,
        "BagsType": "现金钱包",
        "BagsBalance": 10,
        "BagsExpExpireTime": "2025-09-01T00:00:00"
      },]

store。user.ts页——

export const useUserStore = defineStore('user', () => {
  const cardInfo = ref({})
  const isLoading = ref(false)
// 获取并缓存卡片信息
  const fetchCardInfo = async () => {
    if (isLoading.value) return
    isLoading.value = true
    try {
      const res = await cardInfoApi.getCardInfo()
      cardInfo.value = res
      // 将卡片信息也存储到localStorage以便持久化
      localStorage.setItem('cardInfo', JSON.stringify(res))
      return res
    } catch (error) {
      console.error('获取卡片信息失败:', error)
      // 尝试从localStorage读取缓存的卡片信息
      const cachedCardInfo = localStorage.getItem('cardInfo')
      if (cachedCardInfo) {
        cardInfo.value = JSON.parse(cachedCardInfo)
      }
      throw error
    } finally {
      isLoading.value = false
    }
  }
  // 清除缓存数据
  const clearCache = () => {
    cardInfo.value = {}
    localStorage.removeItem('cardInfo')
  }

  return {
    isLoading,
    fetchCardInfo,
    clearCache
  }
})
  • 写回答

4条回答 默认 最新

  • 檀越@新空间 2025-09-22 14:02
    关注

    下午好🌅🌅🌅
    本答案参考通义千问

    在使用 Vue + TypeScript 开发微信公众号应用时,用户信息的缓存与获取策略是非常关键的一环。你已经实现了通过 localStorage 缓存用户信息,并且在多个页面中使用了 computed 属性来处理 cardInfo 的展示逻辑。


    问题总结:

    • 在登录页调用了 fetchCardInfo 接口获取用户信息;
    • 在首页和“我的”页面中需要展示这些信息;
    • 问题在于:是否每次都需要判断是否有缓存内容?还是直接获取即可?

    🧠 核心思路分析:

    1. 数据来源优先级

      • 首选从 store 中获取(即内存中的状态);
      • 如果 store 中没有数据,则尝试从 localStorage 中读取;
      • 如果仍然没有,则调用接口重新拉取;
    2. 避免重复请求

      • 使用 isLoading 控制请求频率,防止多次重复请求;
      • 通过 localStorage 持久化数据,提升用户体验和性能;
    3. 统一数据结构

      • 所有页面都应使用相同的 cardInfo 数据结构,避免因字段缺失导致错误;

    🔍 解决方案:

    1. 统一数据源管理

    userStore 中维护一个统一的 cardInfo 状态,并确保其始终为对象格式。

    export const useUserStore = defineStore('user', () => {
      const cardInfo = ref<Record<string, any>>({}); // 使用 Record 类型确保兼容性
      const isLoading = ref(false);
    
      // 初始化时从 localStorage 加载数据
      onMounted(() => {
        const cachedCardInfo = localStorage.getItem('cardInfo');
        if (cachedCardInfo) {
          cardInfo.value = JSON.parse(cachedCardInfo);
        }
      });
    
      const fetchCardInfo = async () => {
        if (isLoading.value) return;
        isLoading.value = true;
    
        try {
          const res = await cardInfoApi.getCardInfo();
          cardInfo.value = res;
          localStorage.setItem('cardInfo', JSON.stringify(res));
        } catch (error) {
          console.error('获取卡片信息失败:', error);
          // 尝试从 localStorage 读取缓存数据
          const cachedCardInfo = localStorage.getItem('cardInfo');
          if (cachedCardInfo) {
            cardInfo.value = JSON.parse(cachedCardInfo);
          }
          throw error;
        } finally {
          isLoading.value = false;
        }
      };
    
      const clearCache = () => {
        cardInfo.value = {};
        localStorage.removeItem('cardInfo');
      };
    
      return { cardInfo, isLoading, fetchCardInfo, clearCache };
    });
    

    重点说明:

    • 使用 onMounted 初始化时加载 localStorage 中的数据,保证页面初始化时能快速显示已有信息;
    • 统一使用 ref<Record<string, any>> 类型,避免类型不匹配问题。

    2. 页面中统一使用 computed 属性

    在所有需要展示 cardInfo 的页面中,使用 computed 来确保数据结构完整:

    const userStore = useUserStore();
    
    const cardInfo = computed(() => {
      if (userStore.cardInfo && Object.keys(userStore.cardInfo).length > 0) {
        return userStore.cardInfo;
      }
      // 返回默认空对象,避免 undefined 错误
      return {
        CardEndDate: '',
        CardSerNo: '',
        CardTypeName: '',
        balance: '0',
        EmployeeNo: '',
        CardAvailableCredit: 0.00,
        BagsInfo: [{
          BagsID: null,
          BagsType: '',
          BagsBalance: 0.00,
          BagsExpExpireTime: ''
        }]
      };
    });
    

    重点说明:

    • 始终返回一个完整的对象结构,避免在模板中访问不存在的属性;
    • 不要每次都调用 fetchCardInfo,只有在 cardInfo 为空时才触发请求。

    3. 页面加载时判断是否需要拉取数据

    onMounted 中判断是否需要拉取数据:

    onMounted(() => {
      if (!userStore.cardInfo || Object.keys(userStore.cardInfo).length === 0) {
        fetchCardInfoIfNeeded();
      }
    });
    

    重点说明:

    • 只在必要时调用接口,避免不必要的网络请求;
    • 可添加 Loading 提示,提升用户体验。

    4. 优化 fetchCardInfoIfNeeded 函数

    const fetchCardInfoIfNeeded = async () => {
      try {
        await userStore.fetchCardInfo();
        console.log('获取卡片信息成功:', userStore.cardInfo);
      } catch (error) {
        console.error('获取卡片信息失败:', error);
        // 可以在这里提示用户
        // showToast('无法获取最新卡片信息,请稍后再试');
      }
    };
    

    重点说明:

    • 统一使用 userStore.fetchCardInfo(),避免代码重复;
    • 捕获异常并给出友好的提示,提升用户体验。

    最终建议:

    | 页面 | 是否需要判断缓存 | 建议操作 | |------|------------------|----------| | 登录页 | ✅ 需要 | 调用 fetchCardInfo 获取最新信息 | | 首页 | ✅ 需要 | 判断 cardInfo 是否存在,若无则调用 fetchCardInfoIfNeeded | | 我的页 | ✅ 需要 | 同上,使用 computed 属性展示数据 |


    🧩 结论:

    不需要每次都调用接口获取用户信息,只需要在以下情况下触发接口请求:

    • 页面首次加载时,cardInfo 为空;
    • 用户主动刷新或修改信息后;
    • 检测到 localStorage 中的数据过期(如设置有效期);

    推荐做法是:

    • 统一使用 storelocalStorage 缓存数据
    • 使用 computed 属性确保数据结构完整性
    • 只在必要时调用接口,避免重复请求。

    如果你有更多关于微信公众号授权、用户登录流程的问题,也可以继续提问!

    评论

报告相同问题?

问题事件

  • 创建了问题 9月22日