Electron窗口通讯与扩展屏
本期主要介绍扩展屏的开启以及两个窗口之间的消息通讯。在窗口启动部分,我们封装了一个createWindow,用它来创建一个窗口。扩展屏也是一个窗口,只是我们根据有多少显示器放在对应的外屏上。渲染进程我们在渲染进程中添加一个按钮,让它点击,将展开屏幕的操作发送给主进程(打开或隐藏)打开展开屏幕conststate=reactive({open:true,message:''})asyncfunctionopenScreen(){awaitwindow.ipcRenderer.invoke('win-subScreen',{open:state.open,path:'#/subScreen'})state.open=!state.open}主进程接收到后,主进程通过screen.getAllDisplays()获取当前窗口(有几个显示器)的数组,然后获取根据externalDisplay信息显示我们的外屏。同样,我们也使用createWindow创建一个新窗口。之前我们的渲染进程传递了一个路径,这个路径就是我们扩展屏幕要显示的页面。这里需要注意的是createWindow返回的值需要保存在一个全局变量中。之前在托盘里说过,如果是局部变量,函数执行完就会被销毁,窗口也会被销毁。我们这里使用的全局赋值,后面的窗口通信中也会用到,你在这里使用全局变量赋值也是一样的。global.jsglobal.tray=nullglobal.willQuitApp=falseglobal.envConfig={}global.sharedObject={win:'',subScreen:''}exportdefaultglobalimport{ipcMain,app,screen}from'electron'importglobalfrom'../config/global'importcreateWindowfrom'./createWindow'importpathfrom'path'constwin=global.sharedObject.winipcMain.handle('win-subScreen',(_,data)=>{if(data.open){constdisplays=screen.getAllDisplays()constmainBounds=win.getNormalBounds()constexternalDisplay=displays.find((display)=>{returndisplay.bounds.x!==0||display.bounds.y!==0})if(externalDisplay){if(global.sharedObject.subScreen){global.sharedObject.subScreen.show()}else{global.sharedObject.subScreen=createWindow({frame:false,show:false,parent:win,//win是主窗口fullscreen:true,webPreferences:{webSecurity:false,contextIsolation:false,enableRemoteModule:true,nodeIntegration:process.env.ELECTRON_NODE_INTEGRATION,plugins:true,preload:path.join(__dirname,'preload.js'),devTools:false},x:mainBounds.x<0&&数学。abs(mainBounds.x)>(win.getContentSize()[0]/2)?0:externalDisplay.bounds.x,y:externalDisplay.bounds.y},data.path,`index.html${data.path}`)global.sharedObject.subScreen.once('ready-to-show',()=>{global.sharedObject.subScreen.show()})global.sharedObject.subScreen.on('closed',()=>{global.sharedObject.subScreen=null})}}else{console.log('未检测到扩展屏幕')}}else{global.sharedObject.subScreen&&global.sharedObject.subScreen.destroy()}})here有一个小过程。让我们首先确定我们的软件位于哪个屏幕上。比如我们有两个屏幕,1和2,那么我们的主窗口和扩展屏幕就应该在不同的位置。例如:我们的主窗口在1,那么我们的扩展屏幕应该在2打开,如果位置相同同理,由于我们的扩展屏幕设置为全屏,此时主窗口会被遮挡。如果没有设置快捷键关闭,那么扩展屏幕不会关闭,所以下面的处理是constmainBounds=win.getNormalBounds()mainBounds主窗口信息,如果主窗口有一半以上在副屏幕上,那么我们认为主窗口在副屏上,那么扩展屏的打开位置应该在主屏上,否则应该在副屏上。x:mainBounds.x<0&&Math.abs(mainBounds.x)>(win.getContentSize()[0]/2)?0:externalDisplay.bounds.xwindowcommunicationelectorn的窗口之间的通信,一般来说有两种方式。窗口A的渲染进程向主进程发送信息,主进程收到信息后将信息发送给窗口B的渲染进程,即主进程作为中继。在窗口A的渲染过程中,信息是通过窗口B的WebContents.id直接发送给窗口B的。一个promise,在它的resolve中可以得到ipcMain.handle的返回值.on:接收发送信息ipcRenderer.on:接收主进程消息webContents.send:主进程向渲染进程发送消息ipcRenderer.sendTo:可以通过webContentsId直接向相应的渲染进程窗口发送信息。这里我们在渲染过程中同时实现了1和2。在渲染进程中,可以使用remote获取主进程中的全局值。remote.getGlobal('sharedObject').subScreen就是我们之前展开的。纱窗。transferSub是我们的方案1,directSub是方案2。divclass="subMessage">中转发送直接发送
import{defineComponent,reactive,onMounted,onUnmounted,getCurrentInstance}from'vue'const{remote}=require('electron')conststate=reactive({open:true,message:''})const{proxy}=getCurrentInstance()const{$message}=proxyfunctiontransferSub(){window.ipcRenderer.invoke('win-subScreen-message',state.message)}functiondirectSub(){constsubScreen=remote.getGlobal('sharedObject').subScreenif(subScreen){window.ipcRenderer.sendTo(subScreen.webContents.id,'main-subScree',state.message)}}onMounted(()=>{window.ipcRenderer.on('subScree-main',(_event,data)=>{$message.success(data)})})onUnmounted(()=>{window.ipcRenderer.removeListener('subScree-main')})调用主进程,使用webContents.send发送将信息发送到扩展屏幕窗口subScreen-message',data)}})扩展屏幕信息接收和发送我们这里直接监听中继消息和直接发送消息,然后直接通知主窗口消息
{{state.message}} 验证我们打开扩展界面,在主窗口输入信息,点击直接发送或者传输,看看扩展窗口显示的是不是我们输入的信息,主窗口显示的是分屏通知信息系列更新只能在周末和下班时间组织。如果内容多了,更新会慢一些。希望对您有所帮助。请多多star或点赞收藏支持本文。地址:https://xuxin123.com/electron/ipc-subscreen本文github地址:链接