如何将参数从主进程传递到 Electron 中的渲染进程
How to pass parameters from main process to render processes in Electron
我有一个可以打开不同 windows 的 Electron 应用程序。
在应用程序启动时,应用程序打开一组 window(s)(加载相同的 HTML 和 JS 文件)但使用参数来更改每个 window 显示的信息。
示例:
app.on('ready', async () => {
...
// open window for stuff 1
win1 = new BrowserWindow({
width: 1024,
height: 728
});
win1.loadURL(`file://${__dirname}/app/app.html?id=1`);
// open window for stuff 2
win2 = new BrowserWindow({
width: 1024,
height: 728
});
win2.loadURL(`file://${__dirname}/app/app.html?id=2`);
显然在 file:// 路径中传递参数不起作用。
我无法在 Electron 文档或 Internet 上的其他地方找到明确的解决方案来将我呈现的 window 设置为参数。
我可能会在 window 准备好后使用 IPC 通信,但它似乎有点太复杂了,直到我只想将变量传递给我的子视图。
P.S。 : 老实说,我的应用程序是用 React/Redux 构建的,我想传递给视图的参数是用于监听此视图的 redux 存储键。
我们可以注入 Javascript 代码执行(在 window did-finish-load
事件上)并触发反应重新渲染与正确的 redux 状态部分。但在渲染过程中需要额外的生命周期步骤。
在 "local filepath" 中使用散列或查询听起来有点奇怪,但在我的例子中它是有意义的,因为散列描述了 redux 存储分支在这个 window 中考虑(file://which-code-to-load#which-content
).
所以即使我现在对这种方法并不完全放心,我也会选择第二种。
遗憾的是,API 没有提供任何方式在 window 打开时从主进程声明全局变量。我会 post 一个功能请求。
根据 atom 源代码,查询字符串方法是一种非常简单的可靠方法,尤其是当我们只需要传递一个唯一的字符串参数时:
// main process
win1.loadURL(`file://${__dirname}/app/app.html?id=${id}`);
// rendered process
console.log(global.location.search);
不幸的是,它看起来很复杂。您可能无法将变量添加到 .html 您以一种很好的方式在 electron 中渲染。
当然 - 您可以使用 url,但它会大大降低启动速度(vy 秒),或者您可以在 BrowserWindo 中执行 Javascript,这也会减慢启动速度。
唯一的方法是 IPC 并让 javascript .html 对主进程中的变量不可知。虽然很伤心..
几个方法:
loadURL 查询字符串
。它甚至可能是最简单的。
附加参数
Electron 的文档说 additionalArguments
是:
Useful for passing small bits of data down to renderer process preload
scripts.
主要
const win = new BrowserWindow({
width: 800,
height: 600,
backgroundColor: '#000000'
webPreferences: {
additionalArguments: ["myvarvalue", "secondvarvalue", "--another=something"]
}
});
渲染器
window.process.argv
看起来像:
["--num-raster-threads=2",
"--enable-gpu-memory-buffer-compositor-resources",
"--enable-gpu-async-worker-context",
...
"--renderer-client-id=4",
"myvarvalue",
"secondvarvalue",
"--another=something"]
它将追加一个字符串数组。您可以做一些事情 window.process.argv.slice(-3)
来获取数组中的最后一项。
IPC 主要/渲染
就像你说的,你想要做的事情看起来很复杂,但也许这会有所帮助:
主要
const { ipcMain } = require('electron');
var mainProcessVars = {
somevar: "name",
anothervar: 33
}
ipcMain.on('variable-request', function (event, arg) {
event.sender.send('variable-reply', [mainProcessVars[arg[0]], mainProcessVars[arg[1]]]);
});
渲染器
const { ipcRenderer } = electron;
electron.ipcRenderer.send('variable-request', ['somevar', 'anothervar']);
ipcRenderer.on('variable-reply', function (event, args) {
console.log(args[0]); // "name"
console.log(args[1]); // 33
});
这种方式允许您发送字符串以外的数据。
例如:
处理脚本
在你的主脚本中写:
global.varsForWindow = {
platform: process.platform
};
Window 脚本
在 window 脚本中需要它的地方:
var varsFromMainScript = require('electron').remote.getGlobal('varsForWindow');
console.log(varsFromMainScript.platform);
您可以使用 global
变量在主处理器和渲染处理器之间共享数据:
主处理器:
global.id = 1;
渲染处理器:
let id = remote.getGlobal('id');
将查询字符串与 win.loadFile()
、
一起使用
// main process or renderer process 1
data = {"age": 12, "healthy": true}
let win = new BrowserWindow({
webPreferences: {
nodeIntegration: true
}
});
win.loadFile("public/print.html", {query: {"data": JSON.stringify(data)}});
// renderer process 2
const querystring = require('querystring');
let query = querystring.parse(global.location.search);
let data = JSON.parse(query['?data'])
实际上使用调用和句柄组合也可以。在我的例子中,我特别需要在一开始就建立连接。
处于预加载状态
const { ipcRenderer } = require('electron')
window.addEventListener('DOMContentLoaded', () => {
ipcRenderer.invoke('init').then(res => {
window.alert(res)
// render(e(App, {}), elem)
})
})
并且在主要部分
const { ipcMain } = require('electron')
ipcMain.handle('init', async () => {
return 'Abc'
})
您甚至可以尝试通过 ipcRenderer.sendSync
进行同步调用,也许这样更快,但我还没有尝试过。
我有一个可以打开不同 windows 的 Electron 应用程序。
在应用程序启动时,应用程序打开一组 window(s)(加载相同的 HTML 和 JS 文件)但使用参数来更改每个 window 显示的信息。
示例:
app.on('ready', async () => {
...
// open window for stuff 1
win1 = new BrowserWindow({
width: 1024,
height: 728
});
win1.loadURL(`file://${__dirname}/app/app.html?id=1`);
// open window for stuff 2
win2 = new BrowserWindow({
width: 1024,
height: 728
});
win2.loadURL(`file://${__dirname}/app/app.html?id=2`);
显然在 file:// 路径中传递参数不起作用。 我无法在 Electron 文档或 Internet 上的其他地方找到明确的解决方案来将我呈现的 window 设置为参数。
我可能会在 window 准备好后使用 IPC 通信,但它似乎有点太复杂了,直到我只想将变量传递给我的子视图。
P.S。 : 老实说,我的应用程序是用 React/Redux 构建的,我想传递给视图的参数是用于监听此视图的 redux 存储键。
我们可以注入 Javascript 代码执行(在 window did-finish-load
事件上)并触发反应重新渲染与正确的 redux 状态部分。但在渲染过程中需要额外的生命周期步骤。
在 "local filepath" 中使用散列或查询听起来有点奇怪,但在我的例子中它是有意义的,因为散列描述了 redux 存储分支在这个 window 中考虑(file://which-code-to-load#which-content
).
所以即使我现在对这种方法并不完全放心,我也会选择第二种。
遗憾的是,API 没有提供任何方式在 window 打开时从主进程声明全局变量。我会 post 一个功能请求。
根据 atom 源代码,查询字符串方法是一种非常简单的可靠方法,尤其是当我们只需要传递一个唯一的字符串参数时:
// main process
win1.loadURL(`file://${__dirname}/app/app.html?id=${id}`);
// rendered process
console.log(global.location.search);
不幸的是,它看起来很复杂。您可能无法将变量添加到 .html 您以一种很好的方式在 electron 中渲染。
当然 - 您可以使用 url,但它会大大降低启动速度(vy 秒),或者您可以在 BrowserWindo 中执行 Javascript,这也会减慢启动速度。
唯一的方法是 IPC 并让 javascript .html 对主进程中的变量不可知。虽然很伤心..
几个方法:
loadURL 查询字符串
附加参数
Electron 的文档说 additionalArguments
是:
Useful for passing small bits of data down to renderer process preload scripts.
主要
const win = new BrowserWindow({
width: 800,
height: 600,
backgroundColor: '#000000'
webPreferences: {
additionalArguments: ["myvarvalue", "secondvarvalue", "--another=something"]
}
});
渲染器
window.process.argv
看起来像:
["--num-raster-threads=2",
"--enable-gpu-memory-buffer-compositor-resources",
"--enable-gpu-async-worker-context",
...
"--renderer-client-id=4",
"myvarvalue",
"secondvarvalue",
"--another=something"]
它将追加一个字符串数组。您可以做一些事情 window.process.argv.slice(-3)
来获取数组中的最后一项。
IPC 主要/渲染
就像你说的,你想要做的事情看起来很复杂,但也许这会有所帮助:
主要
const { ipcMain } = require('electron');
var mainProcessVars = {
somevar: "name",
anothervar: 33
}
ipcMain.on('variable-request', function (event, arg) {
event.sender.send('variable-reply', [mainProcessVars[arg[0]], mainProcessVars[arg[1]]]);
});
渲染器
const { ipcRenderer } = electron;
electron.ipcRenderer.send('variable-request', ['somevar', 'anothervar']);
ipcRenderer.on('variable-reply', function (event, args) {
console.log(args[0]); // "name"
console.log(args[1]); // 33
});
这种方式允许您发送字符串以外的数据。
例如:
处理脚本
在你的主脚本中写:
global.varsForWindow = {
platform: process.platform
};
Window 脚本
在 window 脚本中需要它的地方:
var varsFromMainScript = require('electron').remote.getGlobal('varsForWindow');
console.log(varsFromMainScript.platform);
您可以使用 global
变量在主处理器和渲染处理器之间共享数据:
主处理器:
global.id = 1;
渲染处理器:
let id = remote.getGlobal('id');
将查询字符串与 win.loadFile()
、
// main process or renderer process 1
data = {"age": 12, "healthy": true}
let win = new BrowserWindow({
webPreferences: {
nodeIntegration: true
}
});
win.loadFile("public/print.html", {query: {"data": JSON.stringify(data)}});
// renderer process 2
const querystring = require('querystring');
let query = querystring.parse(global.location.search);
let data = JSON.parse(query['?data'])
实际上使用调用和句柄组合也可以。在我的例子中,我特别需要在一开始就建立连接。
处于预加载状态
const { ipcRenderer } = require('electron')
window.addEventListener('DOMContentLoaded', () => {
ipcRenderer.invoke('init').then(res => {
window.alert(res)
// render(e(App, {}), elem)
})
})
并且在主要部分
const { ipcMain } = require('electron')
ipcMain.handle('init', async () => {
return 'Abc'
})
您甚至可以尝试通过 ipcRenderer.sendSync
进行同步调用,也许这样更快,但我还没有尝试过。