使用pinia-plugin-persistedstate持久化File数据遇问题求助
解决Pinia持久化File对象丢失的问题
问题根源
File是浏览器提供的特殊对象,包含文件内容、元数据等信息,但无法被JSON序列化。而pinia-plugin-persistedstate默认使用JSON来持久化Store状态,所以刷新页面后,原本存储的File对象无法被正确恢复,最终变成空Proxy。
解决方案
方案1:存储文件元数据+S3标识(推荐大文件使用)
不直接存储File对象,而是存储文件的元数据(文件名、类型、大小)和S3对象键,刷新页面后通过S3键重新请求文件。
修改后的Store代码:
export const useScanStore = defineStore('scans', { state: () => ({ scanList: [] as PersistedScanInfo[], }), getters: { getScan: (state) => (id: string) => { return state.scanList.find(scan => scan.id === id); }, }, actions: { // 从S3重新获取文件并转为File对象 async fetchScanFile(scan: PersistedScanInfo): Promise<File> { // 替换为你的S3下载接口逻辑 const response = await fetch(`https://your-s3-bucket-url/${scan.s3Key}`); const blob = await response.blob(); return new File([blob], scan.fileName, { type: scan.fileType }); }, // 添加扫描记录时存储元数据和S3键 addScan(id: string, file: File, s3Key: string) { this.scanList.push({ id, s3Key, fileName: file.name, fileType: file.type, fileSize: file.size, }); }, }, persist: true, }); // 持久化存储的结构 interface PersistedScanInfo { id: string; s3Key: string; // S3对象唯一标识 fileName: string; fileType: string; fileSize: number; } // 业务中使用的结构(包含File对象) interface ScanInfo extends PersistedScanInfo { file?: File; }
使用方式:刷新页面后,通过getScan获取到扫描记录,再调用fetchScanFile重新获取File对象。
方案2:将File转为Base64字符串存储(适合小文件)
把File对象转为Base64字符串(可被JSON序列化),持久化后再转回File对象。注意:Base64会比原文件体积大30%左右,且浏览器本地存储有大小限制(通常5-10MB),大文件不建议使用。
修改后的Store代码:
export const useScanStore = defineStore('scans', { state: () => ({ scanList: [] as PersistedScanInfo[], }), getters: { getScan: (state) => (id: string) => { const persistedScan = state.scanList.find(scan => scan.id === id); if (!persistedScan) return null; // 将Base64转回File对象 const byteString = atob(persistedScan.fileBase64.split(',')[1]); const arrayBuffer = new ArrayBuffer(byteString.length); const uint8Array = new Uint8Array(arrayBuffer); for (let i = 0; i < byteString.length; i++) { uint8Array[i] = byteString.charCodeAt(i); } return { id: persistedScan.id, file: new File([uint8Array], persistedScan.fileName, { type: persistedScan.fileType }), } as ScanInfo; }, }, actions: { // 添加扫描记录时将File转为Base64存储 async addScan(id: string, file: File) { const fileBase64 = await new Promise<string>((resolve, reject) => { const reader = new FileReader(); reader.onload = () => resolve(reader.result as string); reader.onerror = reject; reader.readAsDataURL(file); }); this.scanList.push({ id, fileBase64, fileName: file.name, fileType: file.type, }); }, }, persist: true, }); // 持久化存储的结构 interface PersistedScanInfo { id: string; fileBase64: string; fileName: string; fileType: string; } // 业务中使用的结构 interface ScanInfo { id: string; file: File; }
内容的提问来源于stack exchange,提问作者bwright
相关产品推荐
相关产品推荐

