Electron学生备考APP:如何在index.html加载时调用JS函数?
解决Electron备考应用进度控制与按钮状态问题
核心问题分析
<body onload>在Electron渲染进程中可能因加载时序或框架机制失效,改用DOMContentLoaded事件能更可靠地监听DOM初始化完成时机,再读取进度变量控制按钮状态。
实现方案
方案1:本地存储进度(简单快速)
适合不需要严格防篡改的场景,用localStorage持久化进度变量:
HTML结构
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>备考应用</title> </head> <body> <button id="module1Btn">模块1:基础知识</button> <button id="module2Btn">模块2:考点强化</button> <button id="module3Btn">模块3:真题解析</button> <button id="module4Btn">模块4:技巧总结</button> <button id="testBtn">综合测试</button> <script src="./renderer.js"></script> </body> </html>
渲染进程逻辑(renderer.js)
// 监听DOM完全加载事件 document.addEventListener('DOMContentLoaded', () => { // 读取进度,默认0(首次启动) const progress = parseInt(localStorage.getItem('studyProgress')) || 0; // 绑定按钮状态更新 updateButtonStates(progress); // 模块完成后的进度更新逻辑 document.getElementById('module1Btn').addEventListener('click', () => { localStorage.setItem('studyProgress', '1'); updateButtonStates(1); }); document.getElementById('module2Btn').addEventListener('click', () => { localStorage.setItem('studyProgress', '2'); updateButtonStates(2); }); document.getElementById('module3Btn').addEventListener('click', () => { localStorage.setItem('studyProgress', '3'); updateButtonStates(3); }); document.getElementById('module4Btn').addEventListener('click', () => { localStorage.setItem('studyProgress', '4'); updateButtonStates(4); }); document.getElementById('testBtn').addEventListener('click', () => { localStorage.setItem('studyProgress', '5'); updateButtonStates(5); }); }); // 统一管理按钮启用状态 function updateButtonStates(progress) { // 模块1完成后可禁用(可选,防止重复进入) document.getElementById('module1Btn').disabled = progress >= 1; // 后续模块需前序完成才能启用 document.getElementById('module2Btn').disabled = progress < 1; document.getElementById('module3Btn').disabled = progress < 2; document.getElementById('module4Btn').disabled = progress < 3; document.getElementById('testBtn').disabled = progress < 4; }
方案2:主进程托管进度(安全防篡改)
如果需要防止用户手动修改进度,将进度存储在主进程的文件中,通过IPC通信读取/更新:
主进程逻辑(main.js)
const { app, BrowserWindow, ipcMain } = require('electron'); const fs = require('fs'); const path = require('path'); // 进度存储路径(Electron用户数据目录) const progressFile = path.join(app.getPath('userData'), 'study-progress.json'); // 读取进度 function readProgress() { try { const data = fs.readFileSync(progressFile, 'utf8'); return JSON.parse(data).progress || 0; } catch (err) { // 文件不存在或损坏,返回初始进度0 return 0; } } // 保存进度 function writeProgress(progress) { fs.writeFileSync(progressFile, JSON.stringify({ progress })); } let mainWindow; function createWindow() { mainWindow = new BrowserWindow({ width: 800, height: 600, webPreferences: { preload: path.join(__dirname, 'preload.js'), // 预加载脚本暴露API contextIsolation: true, // 启用上下文隔离,提升安全性 nodeIntegration: false } }); mainWindow.loadFile('index.html'); // 响应渲染进程的进度读取请求 ipcMain.handle('get-study-progress', () => readProgress()); // 响应渲染进程的进度保存请求 ipcMain.handle('save-study-progress', (_, progress) => { writeProgress(progress); return true; }); } app.whenReady().then(createWindow);
预加载脚本(preload.js)
通过contextBridge安全暴露主进程API给渲染进程:
const { contextBridge, ipcRenderer } = require('electron'); contextBridge.exposeInMainWorld('studyAPI', { getProgress: () => ipcRenderer.invoke('get-study-progress'), saveProgress: (progress) => ipcRenderer.invoke('save-study-progress', progress) });
渲染进程逻辑修改(renderer.js)
document.addEventListener('DOMContentLoaded', async () => { // 从主进程异步读取进度 const progress = await window.studyAPI.getProgress(); updateButtonStates(progress); // 模块完成时调用主进程保存进度 document.getElementById('module1Btn').addEventListener('click', async () => { await window.studyAPI.saveProgress(1); updateButtonStates(1); }); // 其他按钮逻辑同理... }); // 按钮状态更新函数和方案1一致 function updateButtonStates(progress) { document.getElementById('module1Btn').disabled = progress >= 1; document.getElementById('module2Btn').disabled = progress < 1; document.getElementById('module3Btn').disabled = progress < 2; document.getElementById('module4Btn').disabled = progress < 3; document.getElementById('testBtn').disabled = progress < 4; }
关键注意事项
- 避免直接启用
nodeIntegration,用preload.js+contextBridge是Electron官方推荐的安全实践 - 进度变量取值0-5,对应"未开始→模块1完成→模块2完成→模块3完成→模块4完成→测试完成"的状态
内容的提问来源于stack exchange,提问作者Mike M.
相关产品推荐
相关产品推荐

