【问题标题】:How to pass parameters from main process to render processes in Electron如何将参数从主进程传递到 Electron 中的渲染进程
【发布时间】:2016-11-15 01:22:08
【问题描述】:

我有一个可以打开不同窗口的 Electron 应用。

在应用启动时,应用会打开一组窗口(加载相同的 HTML 和 JS 文件),但使用参数来更改每个窗口显示的信息。

例子:

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 上的其他地方找不到明确的解决方案,以将渲染的窗口调整为参数。

我可能可以在窗口准备好后使用 IPC 通信,但在我只想将变量传递给我的子视图之前,这似乎有点太复杂了。

附: : 老实说,我的应用程序是使用 React/Redux 构建的,我想要传递给视图的参数是用于监听此视图的 redux 存储键。

【问题讨论】:

  • file:// 路径中传递参数(和哈希)对我来说效果很好。正如预期的那样,所有参数都在location 中。
  • 我不会对文件使用这个参数化的 URL 概念,如果你愿意在 HTTP 服务器上提供它们。相反,您可以做不同的事情,例如使用 Cookie,在开始时阅读它们。或者只是使用 win1.webContents.executeJavaScript("var query = {id:1}")... 至少它是一个衬里
  • 我认为你的两个回答都成功了。
  • 我认为向file:// 提供(短)参数没有任何问题;也就是说,我还使用了一个preload 脚本文件,从中我从主线程获取一个(可能很大的)JSON 页面数据字符串,并使其可用于页面。这样页面数据在页面加载期间就已经可用了。
  • 您似乎每 4 小时问一次同样的问题。 youtube.com/watch?v=jKzBJAowmGg

标签: javascript electron


【解决方案1】:

几种方法:

loadURL 查询字符串

The query string method others have posted seems to work fine。它甚至可能是最简单的。

附加参数

Electron 的文档说 additionalArguments 是:

对于将少量数据向下传递到渲染器进程预加载很有用 脚本。

主要

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
});

这种方式可以让你发送字符串以外的数据。

【讨论】:

  • window.process 现在在渲染器中是未定义的,除非webPreferences: { nodeIntegration: true, contextIsolation: false }。见stackoverflow.com/questions/66612493/…
  • @PsychoX process 在渲染器中是未定义的,但它可以在预加载脚本中访问。然后,您可以通过contextBridge 将其(安全地?)暴露给渲染器。
  • additionalArguments 运行良好,但我注意到在 Windows 上(或至少在我同事的设置上)会有一个附加参数 (/prefetch:1) 附加在 之后,所以slice(-3) 不是一种可靠的阅读方式。
【解决方案2】:

根据 atom 源代码,查询字符串方法是一种非常简单的可靠方法,尤其是当我们只需要传递一个唯一的字符串参数时:

// main process
win1.loadURL(`file://${__dirname}/app/app.html?id=${id}`);

// rendered process
console.log(global.location.search);

https://github.com/electron/electron/issues/6504

【讨论】:

  • 最好作为 json 对象接收。有没有办法做到这一点?
  • @MagedSaeed 是的,使用全局变量(在下面查看我的答案)
【解决方案3】:

使用查询字符串和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'])

【讨论】:

  • 查询字符串可以传递多少数据有限制吗?谢谢!
  • @majorBummer 我不确定。我从来没有达到极限。
  • 我一直使用它,直到它被不适当的缓存所困扰。也就是说,location.search 的值(在我的情况下,每次运行程序时都应该不同)将是先前调用的值。
【解决方案4】:

我们可以注入 Javascript 代码执行(在窗口 did-finish-load 事件上)并使用正确的 redux 状态部分触发重新渲染。但在渲染过程中需要额外的生命周期步骤。

在“本地文件路径”中使用散列或查询听起来有点奇怪,但在我的情况下,这是有道理的,因为散列描述了要在此窗口中考虑的 redux 存储分支 (file://which-code-to-load#which-content)。

所以即使我现在对这种方法并不完全放心,我也会选择第二种选择。

很遗憾,API 没有提供任何方法来在打开窗口时从主进程声明全局变量。我将发布功能请求。

【讨论】:

  • 你能详细说明/举例说明这些方法是如何工作的吗?
【解决方案5】:

例如:

处理脚本

在你的主脚本中写:

global.varsForWindow = {
    platform: process.platform
};

窗口脚本

在窗口脚本中需要它的地方:

var varsFromMainScript = require('electron').remote.getGlobal('varsForWindow');
console.log(varsFromMainScript.platform);

【讨论】:

  • 如果您需要将不同的值传递给不同的窗口,则不起作用...
【解决方案6】:

您可以使用global 变量在主处理器和渲染处理器之间共享数据:

主处理器:

global.id = 1;

渲染器处理器:

let id = remote.getGlobal('id');

【讨论】:

  • 我不推荐这种方式。如果开发者想要连续创建多个窗口。
  • 远程模块已被弃用,不再推荐使用
  • 此外,什么是远程?另一个全球?
【解决方案7】:

实际上使用调用和句柄组合也可以。在我的例子中,我特别需要在一开始就建立连接。

预加载中

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 进行同步调用,也许这样更快,但我没有尝试过。

【讨论】:

    【解决方案8】:

    不幸的是,它看起来相当复杂。您可能无法以一种不错的方式将变量添加到您在电子中呈现的 .html。

    当然 - 您可以使用 url,但它会大大减慢启动速度(vy 秒),或者您可以在 BrowserWindo 中执行 Javascript,这也会减慢启动速度。

    唯一的方法是 IPC 并让 javascript .html 与主进程中的变量无关。虽然很伤心..

    【讨论】:

      猜你喜欢
      • 2018-01-05
      • 2018-05-29
      • 1970-01-01
      • 2022-01-11
      • 2022-01-15
      • 2020-04-09
      • 2017-06-01
      • 2017-01-22
      • 2019-12-29
      相关资源
      最近更新 更多