电子中 2 个浏览器 windows 之间的通信

communication between 2 browser windows in electron

我需要构建一个跨多个显示器屏幕的应用程序,如下所示: Electron 支持多个 windows 但它们之间如何通信?

主要要记住的是,在Electron中,进程间通信是由ipcMain(在主进程中)和ipcRenderer(在所有创建的windows中)完成的。像下面这样: 从我在 GitHub 评论中看到的情况来看——渲染器实例之间的直接通信是不允许的。一切都必须通过 mainProcess。

代码: mainProcess.js:

function createWindow1 () {
  window1 = new BrowserWindow({width: 800,height: 600})
  window1.loadURL(`file://${__dirname}/window1.html`)
  window1.webContents.openDevTools()
  window1.on('closed', function () {
     window1 = null
  })
  return window1
}
function createWindow2 () {
  window2 = new BrowserWindow({width: 1000, height: 600})
  window2.loadURL(`file://${__dirname}/window2.html`)
  window2.webContents.openDevTools()
  window2.on('closed', function () {
    window2 = null
  })
  return window2
}

app.on('ready', () => {
  window1 = createWindow1();
  window2 = createWindow2();

  ipcMain.on('nameMsg', (event, arg) => {
  console.log("name inside main process is: ", arg); // this comes form within window 1 -> and into the mainProcess
  event.sender.send('nameReply', { not_right: false }) // sends back/replies to window 1 - "event" is a reference to this chanel.
  window2.webContents.send( 'forWin2', arg ); // sends the stuff from Window1 to Window2.
});

window1.html:

<body>
    <input type="text" id="name" value="" placeholder="Enter your name">
    <button type="button" id="sendName" >Send the name! </button>
</body>
<script>
   // You can also require other files to run in this process
   require('./window1.js')
</script>

window1.js:

const ipcRenderer = require('electron').ipcRenderer

let name = document.getElementById('name');

ButtonSendName = document.getElementById('sendName');
ButtonSendName.addEventListener('click', (event) => {
  ipcRenderer.send('nameMsg', name.value);
})

ipcRenderer.on('nameReply', (event, arg) => {
  console.log(arg) // why/what is not right..
});

window2.html:

<body>
  <p id = "showName"></p>
</body>

<script>
  require('./window2.js')
</script>

window2.js:

const { ipcRenderer } = require('electron')

showName = document.getElementById('showName')
ipcRenderer.on('forWin2', function (event, arg){
  console.log(arg);
  showName.innerHTML = arg;
});
console.log("I'm Window2");

有演示会更好,但我不知道如何构建电子 CodeBin 应用程序。这张图片给你一个想法:

享受电子的力量!

根据您的要求...可以创建 SharedWorker 作为在 windows 之间传输 MessagePort 的代理。注意:SharedWorker 要求所有 windows 运行 来自同一来源(可能不符合您的要求)。因此,例如,在主 window 中创建一个 MessageChannel(它提供了两个端口),然后通过 SharedWorker 将 port1 传输到一个 window,将 port2 传输到另一个 window。现在两个 windows 可以使用 postMessage 通过端口直接通信。作为奖励,postMessage 还支持 transferables。我一直在考虑这个想法,但还没有完全开发这个库,但你可以从这里正在进行的一些工作中得到这个想法:https://github.com/lneir/electron-direct-comm

每当我们谈论在 Electron 应用程序中从一个 window 到另一个 window 的通信时,您总是会想到 IPC 系统,即进程间通信。

因此,在一个 window 中,您将监听一个事件,例如表单提交。

提交表单后,您可以从该输入中取出文本并向 Electron 应用程序发出事件。

然后 Electron 应用程序将触发自己的事件并将事件发送到 mainWindow,后者将接收文本并将其附加到其列表中。

您可以像这样在辅助 window.html 文件中仅使用 vanilla JavaScript 开始此操作:

  document.querySelector('form').addEventListener('submit', event => {
    event.preventDefault();
  });

以上内容假设您正在使用您尝试提交的表单。

编辑:我为此创建了一个存储库:electron-multi-monitor

我们的项目遇到了类似的问题。然而,两个浏览器Windows 都必须来回传递 JS 对象和函数。

通过 IPC 调用提出的解决方案是我们尝试的第一件事,但还不够。当你只需要传递一些小对象时它工作得很好,但你很快就会达到它的极限,因为 Electron 将序列化通过 IPC 调用传递的所有数据。

我们前进的方式是使用 window.opener 功能。我们使用 electron 生成一个 main BrowserWindow,然后通过 window.open() 打开所需数量的 side 浏览器 Windows。 Electron 可以在它们生成时定位那些 windows。 接下来每个 side window 将注册它的 HTML DOM 作为它的 JS window 实例与 main window。这样 main window 就可以引用 side windows' DOM 和 JS window 实例。 从这里开始,main window 可以完全控制所有可用的 windows,并且可以渲染新的 HTML,传递 JS 对象,调用 JS 函数,...在所有 windows 上。我们个人使用 React Portals 来处理不同 windows.

上的渲染

目前我无法分享完整的示例,但如果我有时间,我会创建一个 github 存储库。

一些已经可以帮助你转发的东西:

  • 浏览器Windows 应该具有相同的 affinity(参见 BrowserWindow docs
  • 启用 nativeWindowOpen 您的 webPreferences

仅供参考:您也可以直接在浏览器中使用此技术,但它们仍然不允许您四处移动 windows

如果你从主 window 的 renderer 进程中打开弹出 window,你实际上可以通过 JS 在 2 个 Electron windows 之间进行通信],通过使用 window.open()。这避免了通过 IPC 调用进行通信的需要。 See Docs.

例如:

//renderer process
let popupWindow = window.open(
  './popup.html', 
  'popup'       
  'width=800,height=600'
);

popupWindow.onload = () => {       
  //now we have access to popup window dom   
  popupWindow.document.body.appendChild(myDomElement);
};

请注意,要使其正常工作,您需要在最初创建主 window.

时设置 nativeWindowOpen webPreferences 选项
// main process
const mainWindow = new BrowserWindow({
  width: 800,
  height: 600,
  webPreferences: {
    nativeWindowOpen: true
  }
})