想问一下 pinia 持久化到 localStorage 如何实现有效期 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
puremaker
V2EX    Vue.js

想问一下 pinia 持久化到 localStorage 如何实现有效期

  •  
  •   puremaker 2025 年 6 月 13 日 3126 次点击
    这是一个创建于 235 天前的主题,其中的信息可能已经有所发展或是发生改变。

    RT ,本人做了款小游戏,把玩家信息存到了 store 里。但是发现如果某个玩家意外退出了,且游戏对局结束了,当这个玩家再打开页面的时候还会被识别为在游戏中,因为他没有经历正常的结束游戏代码,没有去移除掉失效的玩家信息。当然每次重载游戏的时候用玩家信息去核实游戏状态也可以。但是我想知道这个持久化到底能不能设置有效期

    10 条回复    2025-06-16 08:55:35 +08:00
    Troevil
        1
    Troevil  
       2025 年 6 月 13 日
    自己封装一下

    第一种用额外的 key ,val 存储 key 的过期时间
    ```typescript
    // stores/user.ts
    import { defineStore } from 'pinia'

    const EXPIRATION_KEY = '__user_store_expire__'
    const EXPIRATION_DURATION = 1000 * 60 * 60 // 1 小时(可修改)

    export const useUserStore = defineStore('user', {
    state: () => ({
    name: '',
    token: '',
    }),
    persist: {
    key: 'user', // 本地存储的 key
    storage: localStorage,
    afterRestore: (context) => {
    const expireTime = parseInt(localStorage.getItem(EXPIRATION_KEY) || '0')
    const now = Date.now()
    if (now > expireTime) {
    console.log('user store expired, resetting...')
    context.store.$reset()
    localStorage.removeItem(EXPIRATION_KEY)
    }
    },
    // 在每次存储后写入过期时间
    beforeRestore: () => {
    const expireTime = Date.now() + EXPIRATION_DURATION
    localStorage.setItem(EXPIRATION_KEY, expireTime.toString())
    }
    },
    })

    ```

    第二种 直接 warpper 原数据
    ```
    // stores/user.ts
    import { defineStore } from 'pinia'
    import { createPersistedState } from 'pinia-plugin-persistedstate'

    // 设置过期时间(单位:毫秒)
    const EXPIRE_TIME = 1000 * 60 * 60 // 1 小时

    // 封装一个带过期逻辑的 storage
    const expiredStorage = {
    getItem: (key: string): string | null => {
    const raw = localStorage.getItem(key)
    if (!raw) return null

    try {
    const parsed = JSON.parse(raw)
    const now = Date.now()

    if (parsed.expire && now > parsed.expire) {
    localStorage.removeItem(key)
    return null
    }

    return JSON.stringify(parsed.data)
    } catch (e) {
    return null
    }
    },

    setItem: (key: string, value: string): void => {
    const payload = {
    data: JSON.parse(value),
    expire: Date.now() + EXPIRE_TIME,
    }
    localStorage.setItem(key, JSON.stringify(payload))
    },

    removeItem: (key: string): void => {
    localStorage.removeItem(key)
    },
    }



    ```
    runlongyao2
        2
    runlongyao2  
       2025 年 6 月 13 日
    原生 API 肯定没有,得自己加一个存储值
    FrankFang128
        3
    FrankFang128  
       2025 年 6 月 13 日
    当用户来到你的首页,你就应该重置游戏信息了
    DeWjjj
        4
    DeWjjj  
    PRO
       2025 年 6 月 13 日
    存字段的时候就设置一个时间呗,然后上页面就存取,过期就去掉呗。
    VVVYGD
        5
    VVVYGD  
       202 年 6 月 13 日
    前端 localstoreage 与后端存储要做些同步,例如最终一致性。
    chf007
        6
    chf007  
       2025 年 6 月 13 日
    如果只是临时的游戏数据,可以换成持久在 sessionStorage 里么
    xmdbb
        7
    xmdbb  
       2025 年 6 月 13 日
    重新进入时候不应该通过对局 ID 查询对局状态吗....
    好像和持久化有效期没关系吧...
    SanjinGG
        8
    SanjinGG  
       2025 年 6 月 14 日
    看样子,游戏状态没必要持久化吧,你又不断线重新加入对局
    heike8
        9
    heike8  
       2025 年 6 月 15 日 via Android
    存对象加个 ts ,取的时候判断下
    puremaker
        10
    puremaker  
    OP
       2025 年 6 月 16 日
    @xmdbb 正常情况是需要这样设计,我偷了懒,前端存在玩家 id 就认为游戏还在。以后会改
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     4516 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 41ms UTC 05:52 PVG 13:52 LAX 21:52 JFK 00:52
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86