You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Electron中如何在渲染进程间传递持久化全局变量?

MathsTutor 页面数值持久化问题

问题描述

我正在为MathsTutor应用配置持久化变量,用来存储HTML页面生成的数值,确保用户离开页面再返回时能保留这些值。当前用户进入加法等子页面后,点击生成按钮会生成两个随机数,但返回主菜单再回到该页面时,页面会完全重置,无法恢复之前的数字。我尝试用preload脚本通过contextBridge暴露全局变量来长期存储数值,但这个方案没生效。

核心代码片段

main.js

const {app, BrowserWindow, ipcMain, Menu} = require('electron');
const url = require('url');
const path = require('path');

let mainWindow;

const createWindow = () => {
    // 创建窗口
    mainWindow = new BrowserWindow({
        show: false,
        autoHideMenuBar: true,
        webPreferences: ({
            preload: path.join(__dirname, 'scripts', 'preload.js'),
            nodeIntegration: true,
            contextIsolation: false,
        }),
        minWidth: 700,
        minHeight: 400,
    });
    mainWindow.maximize();
    mainWindow.show();

    // 加载HTML到窗口
    mainWindow.loadFile('index.html');
}
...

scripts/preload.js

const {contextBridge} = require('electron');

contextBridge.exposeInMainWorld('integers', {
    m1: 0,
    m2: 0,
    a1: 0,
    a2: 0,
})

scripts/generator.js

const {ipcRenderer} = require('electron');

// 初始化文档变量

// 随机数生成器区域
const digitSelector = document.getElementById('digitSelector');
const randButton = document.getElementById('randomise');
const digitSlider = document.getElementById('digits');
const sliderValue = document.getElementById('sliderValue');
// 题目区域
const problem = document.getElementById('problemBox');
const number1 = document.getElementById('number1');
const number2 = document.getElementById('number2');
const answer = document.getElementById('answer');
const submit = document.getElementById('submit');
const ci = document.getElementById('ci');
// 关闭应用按钮
const closeApp = document.getElementById('closeApp');
// 获取页面标题
const operation = document.title;

let v1;
let v2;
// 用于验证答案的正确结果
let total;


// 生成指定位数的随机整数
const generateRandomInteger = (noOfDigits) => {
...
} 

const makeAnswerable = () => {
    number1.innerText = v1;
    number2.innerText = v2;
    problem.style.visibility = "visible";
    problem.style.opacity = "1";
    problem.style.transform = "translateX(0)";
    digitSelector.style.left = "100%";
    digitSelector.style.transform = "translateX(-100%)";
    ci.innerText = '';
    answer.value = '';
}

// 主要完成五项操作:
// 随机生成页面显示的题目中的两个数字
// 重置答案提示信息并清空答题框
// 设置total为当前题目的正确答案
// 将题目框从顶部横幅后移至可见区域
// 将随机数生成器区域移至屏幕右侧
const randomiseNumbers = (noOfDigits) => {
    v1 = generateRandomInteger(noOfDigits);
    v2 = generateRandomInteger(noOfDigits);
    makeAnswerable();
    if (operation === "Addition") {
        total = v1+v2;
        window.integers.a1 = v1;
        window.integers.a2 = v2;
    }
    else if (operation === "Multiplication") {
        total = v1*v2;
        window.integers.m1 = v1;
        window.integers.m2 = v2;
    }
}

// 点击生成按钮时执行randomiseNumbers
randButton.addEventListener('click', () => {
    const digits = digitSlider.value;
    randomiseNumbers(digits);
});

...

if (operation === "Addition" && window.integers.a1 !== 0) {
    v1 = window.integers.a1;
    v2 = window.integers.a2;
    total = v1+v2;
    makeAnswerable();
}
else if (operation === "Multiplication" && window.integers.m1 !== 0) {
    v1 = window.integers.m1;
    v2 = window.integers.m2;
    total = v1*v2;
    makeAnswerable();
}

pages/addition.html(multiplication.html结构相同,index.html为主菜单)

<!DOCTYPE html>
<html lang="en">
    <head>
...
        <title>Addition</title>
    </head>

    <body>
...
        <div class="mainContent">
            <!-- 随机数生成器盒子 -->
            <div class="digitSelector" id="digitSelector">
                <h3>How many digits would you like the integers to have?</h3>
                <div class="sliderInfo">
                    <input type="range" min="1" max="5" value="3" class="digitSlider" id="digits">
                    <h3 id="sliderValue">3</h3>
                    <button class="randomiser" id="randomise">Generate</button>
                </div>
            </div>
            <!-- 题目盒子(初始位于屏幕外上方) -->
            <div class="problemBox" id="problemBox">
                <h2>Try adding these numbers together:</h2>
                <div>
                    <h3 id="number1"></h3>
                    <h3 id="number2"></h3>
                    <input type="number" class="number" min="0" step="1" max="1000000" id="answer" name="answer" placeholder="Answer here">
                    <input type="submit" id="submit" value="Check answer">
                    <h3 id="ci"></h3>
                </div>
            </div>
        </div>
    </body>

    <script src="../scripts/generator.js"></script>
</html>

问题原因及解决方案

原因分析

你用contextBridge暴露的integers对象是页面级全局变量,当切换页面(从加法页返回主菜单再回来)时,整个页面会重新加载,preload脚本也会重新执行,integers对象会被重置为初始值(m1、m2、a1、a2都回到0),所以之前存储的值会丢失。

解决方案

要实现跨页面的持久化,需要把数据存在主进程或者本地存储中,以下是两种可行方案:

方案1:用Electron的IPC在主进程存储数据

主进程的变量不会随页面刷新而重置,通过IPC通信让渲染进程读写主进程的存储:

  1. 修改main.js,添加存储变量和IPC监听:
// 在main.js顶部定义存储变量
let persistedNumbers = {
    a1: 0,
    a2: 0,
    m1: 0,
    m2: 0
};

// 监听渲染进程的存储请求
ipcMain.on('save-numbers', (event, data) => {
    Object.assign(persistedNumbers, data);
});

// 监听渲染进程的读取请求
ipcMain.handle('get-numbers', () => {
    return persistedNumbers;
});
  1. 修改preload.js,暴露IPC方法给渲染进程:
const {contextBridge, ipcRenderer} = require('electron');

contextBridge.exposeInMainWorld('numberStorage', {
    save: (data) => ipcRenderer.send('save-numbers', data),
    get: () => ipcRenderer.invoke('get-numbers')
});
  1. 修改generator.js中的存储和读取逻辑:
  • 存储部分:
// 替换原来的window.integers赋值
if (operation === "Addition") {
    total = v1+v2;
    window.numberStorage.save({a1: v1, a2: v2});
}
else if (operation === "Multiplication") {
    total = v1*v2;
    window.numberStorage.save({m1: v1, m2: v2});
}
  • 读取部分:
// 替换原来的初始化判断
window.numberStorage.get().then(stored => {
    if (operation === "Addition" && stored.a1 !== 0) {
        v1 = stored.a1;
        v2 = stored.a2;
        total = v1+v2;
        makeAnswerable();
    }
    else if (operation === "Multiplication" && stored.m1 !== 0) {
        v1 = stored.m1;
        v2 = stored.m2;
        total = v1*v2;
        makeAnswerable();
    }
});

方案2:用浏览器本地存储(localStorage)

这种方案更简单,直接用浏览器的localStorage存储数据,不需要主进程参与:

  1. 修改generator.js中的存储和读取逻辑:
  • 存储部分:
if (operation === "Addition") {
    total = v1+v2;
    localStorage.setItem('additionNumbers', JSON.stringify({a1: v1, a2: v2}));
}
else if (operation === "Multiplication") {
    total = v1*v2;
    localStorage.setItem('multiplicationNumbers', JSON.stringify({m1: v1, m2: v2}));
}
  • 读取部分:
if (operation === "Addition") {
    const stored = JSON.parse(localStorage.getItem('additionNumbers'));
    if (stored && stored.a1 !== 0) {
        v1 = stored.a1;
        v2 = stored.a2;
        total = v1+v2;
        makeAnswerable();
    }
}
else if (operation === "Multiplication") {
    const stored = JSON.parse(localStorage.getItem('multiplicationNumbers'));
    if (stored && stored.m1 !== 0) {
        v1 = stored.m1;
        v2 = stored.m2;
        total = v1*v2;
        makeAnswerable();
    }
}

两种方案都能实现跨页面持久化:主进程存储的优势是数据完全由应用控制,不会被浏览器缓存清理影响;localStorage的优势是实现简单,默认支持跨会话持久化(关闭应用再打开也保留数据)。


内容的提问来源于stack exchange,提问作者proshanto-c

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.09 09:40:32