需求
- 保存当前图形设计项目到浏览器,用户刷新的时候不会丢弃图形设计页面的设计数据
功能
- 点击保存开启按钮,保存当前项目,刷新时存在项目则重载保存项目,否则创建空白页面
- 关闭保存按钮,刷新时新建空白项目
IndexedDB优点
- 适合大型图形数据和二进制(如图片、SVG、路径)
- 可存储结构化对象、大量数据
- 支持异步读写
- 适合复杂图形系统的数据持久化
IndexedDB缺点
- 原生API基于事件回调,使用复杂,代码冗杂严重,需要使用封装库idb或者Dexie.js提升体验
- Safari(IOS)兼容不好,存在各种Bug限制
- 在DevTools中查看数据很麻烦
- 不支持多设备同步、云同步
- 不适合高频实时数据操作
适用场景
- 存储图元结构复杂的对象(如Paperjs生成的JSON对象)
- 需要保存用户多个设计版本(
只保存一个的话更推荐localstorage:localStorage只有5MB存储空间,大数据会setItem失败)
实现方案
- 通过Redux,使用redux-persist继承IndexedDB实现全局状态持久化
实现步骤
IndexedDB简单应用
-
使用idb简化IndexedDB操作
npm install idb -
新建工具文件 `services/indexedDBService.ts
import { openDB } from "idb"; const DB_NAME = "tcs_projects"; const STORE_NAME = "projects"; export const initDB = async () => { return await openDB(DB_NAME, 1, { upgrade(db) { if (!db.objectStoreNames.contains(STORE_NAME)) { db.createObjectStore(STORE_NAME); } }, }); }; export const getProjectFromDB = async (key: string) => { const db = await initDB(); return await db.get(STORE_NAME, key); }; export const saveProjectToDB = async (key: string, data: any) => { const db = await initDB(); await db.put(STORE_NAME, data, key); };保存当前修改
saveProjectToDB("current_project", currentProjectData);刷新时加载数据库中项目
const loadProjectFromDB = async () => { const project = await getProjectFromDB("current_project"); if (project) { paper.project.importJSON(project as any); } }; loadProjectFromDB();
一些尝试
-
将保存数据到IndexedDB放在刷新前的监听beforeunload中
beforeunload事件中只会等待同步操作,异步操作(如await、IndexedDB、fetch等)不会被等待执行完成。
优化点
- 不直接保存不可序列化的paper.project到indexedDB中,通过简化提取可序列化结构