在electron中进行使用ipcMain和ipcRenderer模块,通过开发人员定义的通道传递消息来进行通信。新的版本中electron推荐使用上下文隔离渲染器进程进行通信,这种方式的好处是无需在渲染进程中直接使用ipcRenderer发送消息,这种在渲染进程中调用nodejs对象的方法对于渲染进程有侵入性。当我们使用vue或者其他前端框架开发界面时,上下文隔离方式使用起来更加方便,基本上感受不到electron对前端框架的影响。 上下文隔离的进程间通信方式有四种:1。渲染器进程到主进程(单向) 要将单向IPC消息从渲染器进程发送到主进程,您可以使用ipcRenderer。sendAPI发送消息,然后使用ipcMain。onAPI接收。通常使用场景是从Web向主进程发送消息。使用ipcMain。on监听事件 在主进程中,使用ipcMain。on在settitle通道上设置一个IPC监听器:consthandleSetTitle(event,title){constwebContentsevent。senderconstwinBrowserWindow。fromWebContents(webContents)win。setTitle(title)}ipcMain。on(settitle,handleSetTitle) 上面的handleSetTitle回调函数有两个参数:一个IpcMainEvent结构和一个title字符串。每当消息通过settitle通道传入时,此函数找到附加到消息发送方的BrowserWindow实例,并在该实例上调用win。setTitle函数设置窗口标题。通过预加载脚本暴露ipcRenderer。send 要将消息发送到上面创建的监听器,您可以使用ipcRenderer。send。默认情况下,渲染器进程没有权限访问Node。js和Electron模块。作为应用开发者,你需要使用contextBridge来选择要从预加载脚本中暴露哪些API。 在您的预加载脚本中添加以下代码,向渲染器进程暴露一个全局的window。electronAPI变量。import{contextBridge,ipcRenderer}fromelectroncontextBridge。exposeInMainWorld(electronAPI,{setTitle:(title)ipcRenderer。send(settitle,title)}) 然后我们就能够在渲染器进程中使用window。electronAPI。setTitle()函数。构建渲染器进程UI 在BrowserWindow加载的我们的HTML文件中,添加一个由文本输入框和按钮组成的基本用户界面:!DOCTYPEhtmlhtmlheadmetacharsetUTF8!https:developer。mozilla。orgenUSdocsWebHTTPCSPmetahttpequivContentSecurityPolicycontentdefaultsrcself;scriptsrcselftitleHelloWorld!titleheadbodyTitle:inputidtitlebuttonidbtntypebuttonSetbuttonbodyhtml 为了使这些元素具有交互性,我们将在导入的renderer。js文件中添加几行代码,以利用从预加载脚本中暴露的window。electronAPI功能:constsetButtondocument。getElementById(btn)consttitleInputdocument。getElementById(title)setButton。addEventListener(click,(){consttitletitleInput。valuewindow。electronAPI。setTitle(title)}); 这种方式只能把消息从web中发送到主进程,并不能从主进程中获取到返回值。2。渲染器进程到主进程(双向) 双向IPC的一个常见应用是从渲染器进程代码调用主进程模块并等待结果。这可以通过将ipcRenderer。invoke与ipcMain。handle搭配使用来完成。 我们依然通过一个示例来了解这种通信方式:使用ipcMain。handle监听事件 在主进程中,我们将创建一个handleFileOpen()函数,它调用dialog。showOpenDialog并返回用户选择的文件路径值。每当渲染器进程通过dialog:openFile通道发送ipcRender。invoke消息时,此函数被用作一个回调。然后,返回值将作为一个Promise返回到最初的invoke调用。asyncfunctionhandleFileOpen(){const{canceled,filePaths}awaitdialog。showOpenDialog()if(canceled){return}else{returnfilePaths〔0〕返回文件名给渲染进程}}ipcMain。handle(dialog:openFile,handleFileOpen)通过预加载脚本暴露ipcRenderer。invoke 在预加载脚本中,我们暴露了一个单行的openFile函数,它调用并返回ipcRenderer。invoke(dialog:openFile)的值。import{contextBridge,ipcRenderer}fromelectroncontextBridge。exposeInMainWorld(electronAPI,{openFile:()ipcRenderer。invoke(dialog:openFile)})构建渲染器进程UI 在渲染器中调用window。electronAPI。openFile调用打开文件对话框,并获取打开的文件名,并显示在界面上。!DOCTYPEhtmlhtmlheadmetacharsetUTF8!https:developer。mozilla。orgenUSdocsWebHTTPCSPmetahttpequivContentSecurityPolicycontentdefaultsrcself;scriptsrcselftitleDialogtitleheadbodybuttontypebuttonidbtnOpenaFilebuttonFilepath:strongidfilePathstrongbodyhtml 渲染器进程脚本constbtndocument。getElementById(btn)constfilePathElementdocument。getElementById(filePath)btn。addEventListener(click,async(){constfilePathawaitwindow。electronAPI。openFile()filePathElement。innerTextfilePath})3。主进程到渲染器进程(双向) 将消息从主进程发送到渲染器进程时,需要指定是哪一个渲染器接收消息。消息需要通过其WebContents实例发送到渲染器进程。此WebContents实例包含一个send方法,其使用方式与ipcRenderer。send相同。使用webContents模块发送消息 在菜单中通过使用webContents。send将IPC消息从主进程发送到目标渲染器。constmenuMenu。buildFromTemplate(〔{label:app。name,submenu:〔{click:()mainWindow。webContents。send(updatecounter,1),label:Increment,},{click:()mainWindow。webContents。send(updatecounter,1),label:Decrement,}〕}〕)Menu。setApplicationMenu(menu)通过预加载脚本暴露ipcRenderer。on 使用预加载脚本中的contextBridge和ipcRenderer模块向渲染器进程发送消息:import{contextBridge,ipcRenderer}fromelectroncontextBridge。exposeInMainWorld(electronAPI,{onUpdateCounter:(callback)ipcRenderer。on(updatecounter,callback)}) 加载预加载脚本后,渲染器进程应有权访问window。electronAPI。onUpdateCounter()监听器函数。构建渲染器进程UI!DOCTYPEhtmlhtmlheadmetacharsetUTF8!https:developer。mozilla。orgenUSdocsWebHTTPCSPmetahttpequivContentSecurityPolicycontentdefaultsrcself;scriptsrcselftitleMenuCountertitleheadbodyCurrentvalue:strongidcounter0strongbodyhtml 更新HTML文档中的值constcounterdocument。getElementById(counter)window。electronAPI。onUpdateCounter((event,value){constoldValueNumber(counter。innerText)constnewValueoldValuevaluecounter。innerTextnewValue})返回一个回复 对于从主进程到渲染器进程的IPC,没有与ipcRenderer。invoke等效的API。不过,您可以从ipcRenderer。on回调中将回复发送回主进程。 在渲染器进程中,使用event参数,通过countervalue通道将回复发送回主进程。constcounterdocument。getElementById(counter)window。electronAPI。onUpdateCounter((event,value){constoldValueNumber(counter。innerText)constnewValueoldValuevaluecounter。innerTextnewValueevent。sender。send(countervalue,newValue)发送消息到主进程}) 在主进程中,监听countervalue事件并适当地处理它们。。。。ipcMain。on(countervalue,(event,value){console。log(value)将打印到Node控制台})。。。4。渲染器进程到渲染器进程 没有直接的方法可以使用ipcMain和ipcRenderer模块在Electron中的渲染器进程之间发送消息。为此,我们有两种选择:将主进程作为渲染器之间的消息代理。这需要将消息从一个渲染器发送到主进程,然后主进程将消息转发到另一个渲染器。从主进程将一个MessagePort传递到两个渲染器。这将允许在初始设置后渲染器之间直接进行通信。Electron与Vue进程通信 上面我们介绍了Electron的四种进程间通信方式,那么将Electron和Vue结合起来,其本质依然是主进程与渲染进程之间的通信,通信方式不会由什么变化,只是目前比较流行的TS编程方式会让一些人束手无策,会报一些属性不存在的错误,这就需要我们去为TS声明这些额外的属性。例如:注册上下文隔离接口 在预加载脚本中添加如下代码:importosfromos;import{contextBridge}fromelectron;contextBridge。exposeInMainWorld(electronAPI,{platform:os。platform(),}); 2。为TS声明类型srctypesglobal。d。tsexportinterfaceIElectronAPI{platform:string;}declareglobal{interfaceWindow{electronAPI:IElectronAPI;}} 3。在Vue中调用接口srcApp。vuetemplateimgaltVuelogosrca2020imgdataimg。jpgdatasrcimg02。bs178。combgcj40b8560f1b6fe433。jpgHelloWorld:msgHelloVue3TypeScriptVitein{platform}template