用vite去生成electron项目后,分为三个文件夹,main:主进程,preload:预加载,renderer:渲染进程,main下面只有一个ts文件为index.ts,包含了初级创建窗口,展示,还有环境检测等,如果electron中渲染进程与主进程进行通信:
渲染进程里写:
window.electron.ipcRenderer.invoke('render-to-main')
主进程接收:
ipcMain.handle('render-to-main',(a,b)=>{
})
这里可以理解为在主进程声明定义了一个事件,名字叫做render-to-main,在渲染进程中进行调用,调用后会触发(a,b)=>{},这个回调函数,其中a这个参数代表了event事件对象,这个位置是固定的,如果说要渲染进程向主进程传值,那么穿过来的值会在b这个对象里面,a打印出来为:
渲染进程向主进程传值:
window.electron.ipcRenderer.invoke('render-to-main',{
name:'newWina'
})
主进程接收打印出来b为:
ipcMain.handle('render-to-main',(a,b)=>{
console.log('b')
})
在项目开发中,我们对窗口的操作,一般有,显示,隐藏,打开,关闭,等等,如果每个渲染进程通信都写在main文件下的index.ts里面,文件就会变得臃肿且后期不好维护,这时我们就要封装main主进程里的窗口+通信
1.封装主进程里的窗口
在main文件夹下创建一个文件夹名为frame:窗口
frame窗口的意思,顾名思义,里面存储的就是需要封装的窗口函数,例如:我想要一个A窗口,在我点击按钮的时候打开,点击关闭按钮的时候隐藏,接着我又有个b窗口需要打开或者隐藏,如果要写在index.ts里面的话,渲染进程通信的那个窗口,触发的那个事件,还有窗口本身的一些操作就及其复杂且难以维护,所以我们需要去把每个窗口都做一个自己的封装,例如a窗口就在frame文件夹下创建一个aFrame.ts,b窗口就创建一个bFrame.ts,每个ts中都是对应窗口的一个ES6封装的类
上面引入的join,icon,BrowserWindow,还有is是干什么用的呢?主要是用来创建窗口,在AFrame这个类中我们封装了4个自定义的属性#frame,#width,#height,#url,并且封装了4个方法,分别是创建方法,关闭方法,显示方法和隐藏方法,用来,创建窗口,关闭窗口,显示窗口和隐藏窗口
其中,创建窗口需要封装的函数为最开始main文件夹下的index.ts里面的创建窗口函数
把BrowserWindow这个窗口给定义和创建出来,并且用AFrame这个类里的属性去控制BrowserWindow方法里的变量,例如上图,我可以利用#width,#height去控制我要创建的A窗口的宽和高等,这里的webPreferences是不能删除的,因为它的作用是把主进程electron通过预加载传递给渲染进程,如果删除了,在渲染进程中就无法通过window.electron获取electron对象,注意:import引入的路劲因为放到了frame文件夹里面,所以对应的路径也应该跟着改变,如果需要的话也可以去vite.config中去配置短路径,如下图:
此时就已经封装好了A窗口了,那我们要怎么使用这个封装好的类呢?
2.在主进程main文件夹下的index.ts中使用封装好的窗口
2.1引入AFrame这个类
2.2使用A窗口
ipcMain.handle('render-to-main',(e,data)=>{
let aFrame = new AFrame()
aFrame.create()
})
这样就成功的使用了自定义封装的A窗口,后续如果还要对该窗口进行其他操作,就可以直接去A窗口文件里面进行方法的封装就可以了
接着就遇到了第二个问,如果有许多个渲染进程要向主进程通信,难道每次都要去ipcMain.handle中new一个窗口对象,然后再调用该对象的create方法吗?
这显然也不好管理,此时就可以去封装我们的ipcMain.handle中的方法调用了
3.封装Router文件与使用
3.1创建Router文件
在main文件夹下创建一个文件夹叫做router,并且在router文件夹下创建三个ts文件,分别是EventRoute.ts,EventRouter.ts,router.template.ts,如下图所示:
3.2封装的思想
我们正常渲染进程向主进程进行通信,第一是要判断是那个渲染进程向主进程进行的通信,如何判断呢?
1.利用不同的事件名进行判断,例如:
渲染进程里写:
window.electron.ipcRenderer.invoke('Arender-to-main')
主进程接收:
ipcMain.handle('Arender-to-main',(a,b)=>{
})
渲染进程里写:
window.electron.ipcRenderer.invoke('Brender-to-main')
主进程接收:
ipcMain.handle('Brender-to-main',(a,b)=>{
})
2.利用渲染进程所传的值进行判断,例如:
A渲染进程里写:
window.electron.ipcRenderer.invoke('render-to-main',{
name:'newWina'
})
B渲染进程里写:
window.electron.ipcRenderer.invoke('render-to-main',{
name:'newWinb'
})
主进程接收打印出来b为:
ipcMain.handle('render-to-main',(a,b)=>{
if(b.name == 'newWina'){
}else if(b.name == 'newWinb'){
}
})
上述两种写法都比较繁杂,且不好维护,所以我们可以去封装一下
封装的中心思想使用的是传值封装的思想,也就是上面的第二点这种方法去进行一个封装
4.封装EventRouter.ts文件
写一个类,名字叫做EventRouter,也就是我们的事件路由对象,router故名思意,类似于vue里面的router,代表了所有的路由而route表示的是单个路由,这里我们给EventRouter封装了两个属性,#api与routers=[],与三个方法,第一个方法是addApi(),第二个方法是addRoutesrs,第三个方法是router,分别有什么作用呢?
4.1EventRouter添加对象与使用
如果要分辨是那个渲染进程传值给主进程,我们要通过渲染进程的值去分辨,如何拿到这个值呢,就可以使用EventRouter.addApi方法,拿到渲染进程传给主进程的值,如何使用呢?
4.1.1引入routers
这里的routers输出结果为:
这是怎么来的呢?让我们查看router.template.ts,此时可以看到
在template这个文件里面我们引入了route,并且创建了一个数组名字为routers,接着给这个数组去添加一个eventroute对象,可以理解为将单个的路由添加进去router里面,组合成全部的路由,添加了之后routes这个数组里面就有三个对象所构成,每个对象又包含了一个name和一个回调函数,其中,name为newWinA,newWinB,newWinC,回调函数此时为空,template里面给数组添加的对象中的回调函数,就是最终我们要去调用的函数,那该怎么给这个函数传值并且调用呢?
4.2.1在主进程里先引入
主窗口进行了封装和调用
4.2.2在主进程触发的事件函数前进行传值
// 传递api
eventRouter.addApi('mainWindow',mainWindow)
eventRouter.addApi('app',mainWindow)
eventRouter.addApi('dialog',mainWindow)
eventRouter.addRouters(routers)
ipcMain.handle('Arender-to-main',(a,b)=>{
})
此时,EventRouter类里面的属性#api对象,就变成了
{
'mainWindow':mainWindow,
'app':mainWindow,
'dialog':mainWindow
}
EventRouter类里面的属性routers,就被填充为了
这里可以理解为将需要传的api是什么值,传送给主窗口,因为mainWindow代表主窗口,那渲染进程传递过去的值,由谁接收和判断该执行哪一个呢?
答案是:EventRouter.ts
渲染进程:
const newA = ()=>{
window.electron.ipcRenderer.invoke('render-to-main',{
name:'newWina'
})
}
主进程接收:
// 主进程接收渲染进程消息
ipcMain.handle('render-to-main',(e,data)=>{
// 开始封装渲染进程向主进程通信,主进程接收封装
eventRouter.router(data)
})
此时首先会先遍历routers这个数组
传过来的data,就是我们渲染进程传的值
{ name:'newWina'}
定义一个r,去接收routers这个数组里的所有路由,去进行判断看执行谁
先判断渲染进程传过来的值中的name和routers中的哪一个对象的name相等,并且还要保证该对象的回调函数不为null
这里我们可以看到是routers【0】这个对象是符合的,此时就调用了该对象里面的回调函数,并且把#api和渲染进程传过来的对象data一起传递给了这个回调函数
并且执行这个回调函数
new EventRoute('newWina',(api,data)=>{
api.mainWindow.create()
console.log('newWina');
})
这个里面的api就是#api,data,就是{ name:'newWina'}
api的值为一个对象,里面是:
{
'mainWindow':mainWindow,
'app':mainWindow,
'dialog':mainWindow
}
api.mainWindow.create()
就可以访问到我们的主窗口并创建一个窗口,我们如果要创建的窗口是A窗口:
把这个添加到api中,
接着修改一下router.template.ts中的方法
这里我是直接修改了mainWindow为AWindow,当然也可以在这个里面再push一个对象,这样,就可以灵活的修改了,以上就是初级封装主进程了,因为缺少了路由的懒加载。
相关作者
- 获取点赞0
- 文章阅读量1
评论()