将一些初始数据传递给新 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 对象上创建一个新属性,然后从渲染器进程中引用它,但这听起来不像是真正正确的做法。那么,我应该怎么做呢?
我不确定我是否完全理解您需要做什么,但是您可以使用 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
- 意思是,这两个过程拥有对象的独立版本:
- 您在数据的渲染进程版本上应用到您的对象的更改不会反映到 main 中(反之亦然)
- 您不能传递函数(比如使用它在渲染进程中从 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' 中获取。请注意,它在渲染器上是异步的。
我刚开始学习 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 对象上创建一个新属性,然后从渲染器进程中引用它,但这听起来不像是真正正确的做法。那么,我应该怎么做呢?
我不确定我是否完全理解您需要做什么,但是您可以使用 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
- 意思是,这两个过程拥有对象的独立版本:
- 您在数据的渲染进程版本上应用到您的对象的更改不会反映到 main 中(反之亦然)
- 您不能传递函数(比如使用它在渲染进程中从 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' 中获取。请注意,它在渲染器上是异步的。