Electron待办任务应用如何实现用户数据本地持久化?
Electron待办任务应用数据持久化解决方案
一、先排查localStorage失效的常见原因
如果你的代码里已经用了localStorage但没生效,先检查这几点:
- 数据序列化/反序列化是否正确
- 存数据时必须把对象转成JSON字符串:
// 正确写法 localStorage.setItem('tasks', JSON.stringify(tasksArray)); - 读数据时要解析回对象:
// 正确写法 const tasks = JSON.parse(localStorage.getItem('tasks') || '[]');
- 存数据时必须把对象转成JSON字符串:
- 加载时机是否正确
确保在DOM完全加载后再调用LoadDataFromStorage,比如:document.addEventListener('DOMContentLoaded', () => { TaskManager.LoadDataFromStorage(); }); - 窗口配置是否限制了存储
检查main.js的窗口参数,不要禁用浏览器存储相关能力,默认配置即可,不需要额外设置。
二、改用electron-store的具体操作
如果localStorage还是不稳定,推荐用electron-store模块(专门为Electron设计的持久化存储方案,比localStorage更可靠,支持更多数据类型)。
1. 安装依赖
在项目根目录执行:
npm install electron-store
2. 主进程(main.js)配置
初始化存储实例,并通过IPC通信暴露给渲染进程(安全写法,不建议直接开启nodeIntegration):
const { app, BrowserWindow, ipcMain } = require('electron'); const Store = require('electron-store'); const path = require('path'); // 初始化存储,默认会存在用户目录的应用配置文件夹里 const store = new Store(); function createWindow() { const mainWindow = new BrowserWindow({ width: 800, height: 600, webPreferences: { // 用preload脚本暴露API,安全且符合Electron最新规范 preload: path.join(__dirname, 'preload.js'), contextIsolation: true, nodeIntegration: false } }); mainWindow.loadFile('index.html'); } // IPC通信:获取任务列表 ipcMain.handle('get-tasks', () => { return store.get('tasks', []); // 没有数据时返回空数组 }); // IPC通信:保存新任务 ipcMain.handle('save-task', (_, task) => { const tasks = store.get('tasks', []); tasks.push(task); store.set('tasks', tasks); }); // IPC通信:删除任务 ipcMain.handle('delete-task', (_, taskId) => { const tasks = store.get('tasks', []); const updatedTasks = tasks.filter(task => task.id !== taskId); store.set('tasks', updatedTasks); }); app.whenReady().then(() => { createWindow(); app.on('activate', () => { if (BrowserWindow.getAllWindows().length === 0) createWindow(); }); }); app.on('window-all-closed', () => { if (process.platform !== 'darwin') app.quit(); });
3. 编写preload.js脚本
用来安全地向渲染进程暴露主进程的存储API:
const { contextBridge, ipcRenderer } = require('electron'); contextBridge.exposeInMainWorld('electronStoreAPI', { getTasks: () => ipcRenderer.invoke('get-tasks'), saveTask: (task) => ipcRenderer.invoke('save-task', task), deleteTask: (taskId) => ipcRenderer.invoke('delete-task', taskId) });
4. 渲染进程业务代码修改
修改你的TaskManager类,调用暴露的API:
class TaskManager { // 添加任务 static async AddDataToTable(taskData) { // 先存到electron-store await window.electronStoreAPI.saveTask(taskData); // 动态创建DOM元素 const table = document.getElementById('task-table'); const row = table.insertRow(); row.innerHTML = ` <td>${taskData.title}</td> <td>${taskData.description}</td> <td><button onclick="TaskManager.DeleteTask('${taskData.id}')">删除</button></td> `; } // 删除任务 static async DeleteTask(taskId) { await window.electronStoreAPI.deleteTask(taskId); // 删除对应DOM行 const targetRow = document.querySelector(`button[onclick*="${taskId}"]`).closest('tr'); targetRow?.remove(); } // 加载存储的任务 static async LoadDataFromStorage() { const tasks = await window.electronStoreAPI.getTasks(); const table = document.getElementById('task-table'); tasks.forEach(task => { const row = table.insertRow(); row.innerHTML = ` <td>${task.title}</td> <td>${task.description}</td> <td><button onclick="TaskManager.DeleteTask('${task.id}')">删除</button></td> `; }); } } // DOM加载完成后初始化任务列表 document.addEventListener('DOMContentLoaded', async () => { await TaskManager.LoadDataFromStorage(); }); // 表单提交事件 document.getElementById('task-form').addEventListener('submit', async (e) => { e.preventDefault(); const title = document.getElementById('task-title').value; const description = document.getElementById('task-description').value; // 生成唯一ID const taskData = { id: Date.now().toString(), title, description }; await TaskManager.AddDataToTable(taskData); document.getElementById('task-form').reset(); });
内容的提问来源于stack exchange,提问作者MavapeGZ
相关产品推荐
相关产品推荐

