将一些初始数据传递给新 window 的正确方法是什么?

What's the right way to pass some initial data to a new window?

我刚开始学习 Electron,我正在尝试打开一个文件并在新 window 中显示它。我单击初始(根)window 中的一个按钮,然后打开一个 "open file" 对话框,我可以从中获取文件路径。然后我想打开那个文件,创建一个 window,然后将文件的内容传递给新的 window。我的问题是在 window 准备好时将包含文件内容的字符串放入回调函数;我什至可能吗?我的 main.js 代码:

function createWindow (templateFile, initialData) 
{  console.log("Creating window....")
   newWindow = new BrowserWindow({width: 800,
                                  height: 600,
                                  webPreferences: {preload: path.join(__dirname, 'preload.js'),
                                                   nodeIntegration: true}
                                 })
    newWindow.loadFile(templateFile)
    newWindow.webContents.openDevTools()
//This is what doesn't work; I want to take the initialData argument to the createWindow function, 
//and get it into the 'did-finish-load' callback function
    newWindow.webContents.on('did-finish-load', (event, initialData) => 
    {   windowsArray[newWindow.webContents.id] = newWindow 
        console.log(initialData)
        newWindow.webContents.send("initialDataLoad", initialData)
    })
    newWindow.on('closed', function () {newWindow.object = null})
}

ipcMain.on("new-sheet", (event, gameDefinitionFile) => 
{    console.log("Loading " + gameDefinitionFile)
     let gameDefContents
     fs.readFile(gameDefinitionFile, 'ascii', (err, gameDefContents) => {})
     createWindow("defaultSheet.html", gameDefContents)
})

我听说您可以在 webContents 对象上创建一个新属性,然后从渲染器进程中引用它,但这听起来不像是真正正确的做法。那么,我应该怎么做呢?

完整代码位于 https://gitlab.com/sjbrown8/osiris

我不确定我是否完全理解您需要做什么,但是您可以使用 ready-to-show 事件在显示 window 之前将数据发送到新的 window第一次。

如果数据用于填充现有页面元素,这可能最有意义——尽管我想你没有理由不能用新数据破坏页面上的任何内容——它只是另一个渲染.

While loading the page, the ready-to-show event will be emitted when the renderer process has rendered the page for the first time if the window has not been shown yet.

Main.js

mainWindow.once('ready-to-show', () => {
    Menu.setApplicationMenu(basicMenu);

    let data = "some data that have have read from disk and want to send to this new window"
    mainWindow.webContents.send('message', { "event": "data dump", data: data});
    mainWindow.show()
})

渲染器

ipcRenderer.on('message', (event, arg) => {
  switch (arg.event) {
      case "data dump":

       // just a <textArea> but you could do anything with the data.
      $("#dump").text(arg.data);
      break;
  }
});

webContents 方法应该可以轻松解决您的问题。很简单:预先创建并收集 window 需要的所有数据,然后用这些数据生成 window。

webContents 方法有一些限制,因为您在 main 上创建的 webContents 对象被序列化并发送到 render- 意思是,这两个过程拥有对象的独立版本:

  1. 您在数据的渲染进程版本上应用到您的对象的更改不会反映到 main 中(反之亦然)
  2. 您不能传递函数(比如使用它在渲染进程中从 main 调用函数)

但是使用简单的初始化数据:它很容易理解。

编辑:

当然,发送方法需要一个通道名称和一个可选的对象,即您要发送的数据。你可以这样写一个函数:

sendPersonData(personData) => {
   webContents.send('person-data-updated', personData);
);

或者,如果您想要一个接受回调以灵活发送的函数:

updatePersonData(personData, senderCallback) => {
   updatedPersonData = functionToUpdatePersonData(personData);
   senderCallback(personData);
}

// and use that like so:
updatePersonData({name: 'John Doe'}, sendPersonData);

在渲染器上监听有一大缺点。渲染器只获取一次数据,如果您允许刷新浏览器 window (CTRL+R),则浏览器 window 将丢失数据并且不会再次初始化。

在我看来,让渲染器像这样拉入初始数据更安全:

渲染器

let initialData;
ipcRenderer.invoke('fetch-initial-data')
  .then((data) => initialData = data);

主要

const initialData = createItSomehow();
ipcMain.handle('fetch-initial-data', () => initialData);

这样,当我们刷新屏幕时,数据将始终从 'backend' 中获取。请注意,它在渲染器上是异步的。