
本文详解如何利用 lz-String 库对 json 格式的游戏存档进行高效压缩、存储与还原,实现轻量级、可复制的导入/导出功能,显著减小 localstorage 占用并支持用户手动分享存档字符串。
本文详解如何利用 lz-string 库对 json 格式的游戏存档进行高效压缩、存储与还原,实现轻量级、可复制的导入/导出功能,显著减小 localstorage 占用并支持用户手动分享存档字符串。
在 Web 游戏开发中,提供“导出存档”和“导入存档”功能不仅能提升用户体验,还能增强数据可迁移性与社区互动性(例如玩家间交换通关进度)。但直接 JSON.stringify() 后存入 localStorage 存在明显缺陷:数据体积大、易被人工误读/篡改、不便于粘贴分享。此时,LZ-String 是业界广泛采用的轻量级解决方案——它专为 javaScript 设计,无需依赖服务端,纯前端即可完成高压缩比的无损压缩与解压,且输出为可打印字符(UTF-16 安全),非常适合生成用户友好的存档字符串。
✅ 快速集成 LZ-String
首先,通过 CDN 引入官方库(推荐使用 SRI 完整校验):
<script src="https://cdnjs.cloudflare.com/ajax/libs/lz-string/1.4.4/lz-string.js" integrity="sha512-uKcuHr0POVc2zz1hMVTEiicF9G5SPq2k6l4xVmPeSXm8yH/rrM6ewau/Gn89ykaGrfMyhCBH4Vn/MDcS3Pccqw==" crossorigin="anonymous" referrerpolicy="no-referrer"> </script>
⚠️ 注意:LZ-String 的 compress() 输出是 二进制安全字符串(不是 Base64),不可与 btoa() 混用;若需 URL 或邮件兼容格式,请使用 compressToBase64() 和 decompressFromBase64()。
? 实现压缩版存档逻辑
以下为优化后的 saveGame() 与 loadGame() 函数,兼顾健壮性与可读性:
立即学习“Java免费学习笔记(深入)”;
function saveGame() { const game_data = { stars: Game.stars, totalStarsEarned: Game.totalStarsEarned, buildings: buildings, upgrades: upgrades, achievements: achievements, // ✅ 建议添加版本标识,便于未来格式升级兼容 version: 1.3, timestamp: Date.now() }; try { const json = JSON.stringify(game_data); const compressed = LZString.compress(json); // 输出紧凑 UTF-16 字符串 localStorage.setItem("game_data_lz", compressed); console.log("✅ 游戏已压缩保存(LZ-String)"); } catch (e) { console.error("❌ 存档压缩失败:", e); } } function loadGame() { const str = localStorage.getItem("game_data_lz"); if (!str) { console.warn("⚠️ 未找到本地存档"); return false; } try { const decompressed = LZString.decompress(str); if (!decompressed) { throw new Error("解压失败:无效压缩数据"); } const savedGame = JSON.parse(decompressed); // ✅ 安全赋值:仅覆盖目标属性,避免污染全局状态 if (savedGame.stars !== undefined) Game.stars = savedGame.stars; if (savedGame.totalStarsEarned !== undefined) Game.totalStarsEarned = savedGame.totalStarsEarned; if (Array.isArray(savedGame.buildings)) buildings = savedGame.buildings; if (Array.isArray(savedGame.upgrades)) upgrades = savedGame.upgrades; if (Array.isArray(savedGame.achievements)) achievements = savedGame.achievements; console.log("✅ 存档加载成功,版本:", savedGame.version); return true; } catch (e) { console.error("❌ 存档加载失败:", e); return false; } }
? 导出/导入字符串:用户交互层示例
为支持用户复制粘贴,补充两个实用函数:
// 导出为可分享字符串(自动复制到剪贴板) function exportSave() { const str = localStorage.getItem("game_data_lz"); if (!str) return; navigator.clipboard.writeText(str) .then(() => alert("✅ 存档已复制!可粘贴至其他设备导入")) .catch(err => console.error("? 复制失败:", err)); } // 从用户输入字符串导入 function importSave(saveString) { if (!saveString || typeof saveString !== 'string') return false; try { const decompressed = LZString.decompress(saveString); const data = JSON.parse(decompressed); // 此处调用 loadGame 的核心逻辑,或直接赋值 localStorage.setItem("game_data_lz", saveString); loadGame(); return true; } catch (e) { alert("❌ 导入失败:无效存档格式或版本不兼容"); return false; } }
? 注意事项与最佳实践
- 永远校验解压结果:LZString.decompress() 对非法输入返回 NULL,必须判空后再 JSON.parse();
- 添加 version 字段:当游戏数据结构变更时,可在 loadGame() 中检查 savedGame.version 并执行迁移逻辑;
- 避免压缩空/极小数据:LZ-String 对短字符串可能膨胀,建议 >100 字符再启用压缩(可加长度判断);
- 不要替代加密:LZ-String 是压缩,非加密;敏感数据需额外 AES 加密(如使用 CryptoJS);
- 兼容性提示:LZ-String 支持所有现代浏览器(包括 IE10+),无 polyfill 依赖。
通过以上实现,你的 Web 游戏将具备专业级存档管理能力:单字符串导出、毫秒级压缩、跨设备无缝导入,并为后续扩展(如云同步、版本回滚)奠定坚实基础。