【问题标题】:How to pass the window through ipcRenderer.send()?如何通过 ipcRenderer.send() 传递窗口?
【发布时间】:2021-06-06 12:22:12
【问题描述】:

我正在使用 Electron 12.0.0 构建一个多窗口应用程序并尝试使用最新的默认值(nodeIntegration = false,contextIsolation = true)。我试图弄清楚每个渲染器进程应该如何告诉主进程哪个窗口正在发送 IPC 消息。当我尝试通过执行以下操作将 window 对象作为参数传递给 ipcRenderer.send() 时,出现错误(如下所示):

window.api.receive('save', () => {
  window.api.send('save-file', window, markdownView.value)
})

window.api 在preload.js 中定义如下:

const { contextBridge, ipcRenderer } = require('electron')

contextBridge.exposeInMainWorld(
  "api",
  {
    send: (channel, ...args) => {
      const validChannels = [
        'save-file'
      ]
      if (validChannels.includes(channel)) {
        ipcRenderer.send(channel, ...args)
      }
    },
    receive: (channel, func) => {
      const validChannels = [
        'save',
        'file-opened',
        'file-saved'
      ]
      if (validChannels.includes(channel)) {
        // Strip off the event since it includes the sender
        ipcRenderer.on(channel, (event, ...args) => func(...args))
      }
    }
  }
)

一切正常,直到我尝试调用 Save 菜单项(它将save 消息发送到渲染器)并且我在(开发者工具的)控制台中收到以下错误:

[Deprecation] 'window.webkitStorageInfo' is deprecated.                          renderer.js:9
 Please use 'navigator.webkitTemporaryStorage' or 'navigator.webkitPersistentStorage' instead.
(anonymous) @ renderer.js:9
(anonymous) @ VM76 preload.js:22
emit @ VM14 events.js:315
onMessage @ VM75 renderer_init.js:93

Uncaught Error: Uncaught Error: Uncaught Error: An object could not be cloned.
    at EventEmitter.<anonymous> (VM76 preload.js:22)
    at EventEmitter.emit (VM14 events.js:315)
    at Object.onMessage (VM75 renderer_init.js:93)
(anonymous) @ VM76 preload.js:22
emit @ VM14 events.js:315
onMessage @ VM75 renderer_init.js:93

很明显,我做错了什么。我该如何做到这一点,最好不要打开 nodeIntegration 或关闭 contextIsolation?

【问题讨论】:

    标签: javascript electron


    【解决方案1】:

    您不能发送复杂的对象,例如窗口引用。我有一个简单的 2 窗口应用程序,我这样做的方式是有一个消息格式,其中包括一个标识“发件人”的字符串(如下)。我发现消息格式的使用非常灵活且可扩展。

    如果您不想走那么远,可以发送window ID 并在Main 中使用BrowserWindow.fromId(id) 来获取窗口参考。


    渲染器:

    let  arg = { event: "save-project", sender: "editor", data: editorJson };   
    ipcRenderer.send('app-message', arg);
    

    主要

    ipcMain.on('app-message', (event, arg) => {
        switch (arg.event) {
         case 'save-project':
                global.model.data = arg.data;
    
                switch (arg.sender) {
                    case 'editor':
                        timelineWindow.webContents.send('message', { 'event': 'updateData', 'data': global.model.data });
                        break;
                    case 'timeline':
                        if (global.appMode != 'player') {
                            editorWindow.webContents.send('message', { 'event': 'updateData', 'data': global.model.data });
                        }
                        break;
                }
                break;
       }
    }
    

    【讨论】:

    • 谢谢,其他人推荐使用 BrowserWindow.id 字段。在显示窗口之前,每次创建新的 BrowserWindow 时,我都会向渲染器发送一条消息,以便渲染器知道它的 ID。渲染器在每条消息上发送它的 ID,main 维护一个 ID 映射到 Browser Window 实例,以便它可以将 ID 转换回 BrowserWindow。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-12-19
    相关资源
    最近更新 更多