V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
puremaker
V2EX  ›  Vue.js

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

  •  
  •   puremaker · 2 天前 · 1179 次点击

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

    10 条回复    2025-06-16 08:55:35 +08:00
    Troevil
        1
    Troevil  
       2 天前
    自己封装一下

    第一种用额外的 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  
       2 天前
    原生 API 肯定没有,得自己加一个存储值
    FrankFang128
        3
    FrankFang128  
       2 天前
    当用户来到你的首页,你就应该重置游戏信息了
    DeWjjj
        4
    DeWjjj  
       2 天前
    存字段的时候就设置一个时间呗,然后上页面就存取,过期就去掉呗。
    VVVYGD
        5
    VVVYGD  
       2 天前
    前端 localstoreage 与后端存储要做些同步,例如最终一致性。
    chf007
        6
    chf007  
       2 天前
    如果只是临时的游戏数据,可以换成持久在 sessionStorage 里么
    xmdbb
        7
    xmdbb  
       2 天前
    重新进入时候不应该通过对局 ID 查询对局状态吗....
    好像和持久化有效期没关系吧...
    SanjinGG
        8
    SanjinGG  
       1 天前
    看样子,游戏状态没必要持久化吧,你又不断线重新加入对局
    heike8
        9
    heike8  
       1 天前 via Android
    存对象加个 ts ,取的时候判断下
    puremaker
        10
    puremaker  
    OP
       3 小时 8 分钟前
    @xmdbb 正常情况是需要这样设计,我偷了懒,前端存在玩家 id 就认为游戏还在。以后会改
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   4469 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 21ms · UTC 04:04 · PVG 12:04 · LAX 21:04 · JFK 00:04
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.