Electron-vite之主进程的初级封装

收藏

用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打印出来为:

image.png

渲染进程向主进程传值:

window.electron.ipcRenderer.invoke('render-to-main',{

        name:'newWina'

})

主进程接收打印出来b为:

ipcMain.handle('render-to-main',(a,b)=>{

        console.log('b')

})

image.png

在项目开发中,我们对窗口的操作,一般有,显示,隐藏,打开,关闭,等等,如果每个渲染进程通信都写在main文件下的index.ts里面,文件就会变得臃肿且后期不好维护,这时我们就要封装main主进程里的窗口+通信

1.封装主进程里的窗口

在main文件夹下创建一个文件夹名为frame:窗口

image.png

frame窗口的意思,顾名思义,里面存储的就是需要封装的窗口函数,例如:我想要一个A窗口,在我点击按钮的时候打开,点击关闭按钮的时候隐藏,接着我又有个b窗口需要打开或者隐藏,如果要写在index.ts里面的话,渲染进程通信的那个窗口,触发的那个事件,还有窗口本身的一些操作就及其复杂且难以维护,所以我们需要去把每个窗口都做一个自己的封装,例如a窗口就在frame文件夹下创建一个aFrame.ts,b窗口就创建一个bFrame.ts,每个ts中都是对应窗口的一个ES6封装的类

image.png

上面引入的join,icon,BrowserWindow,还有is是干什么用的呢?主要是用来创建窗口,在AFrame这个类中我们封装了4个自定义的属性#frame,#width,#height,#url,并且封装了4个方法,分别是创建方法,关闭方法,显示方法和隐藏方法,用来,创建窗口,关闭窗口,显示窗口和隐藏窗口

其中,创建窗口需要封装的函数为最开始main文件夹下的index.ts里面的创建窗口函数

image.png

把BrowserWindow这个窗口给定义和创建出来,并且用AFrame这个类里的属性去控制BrowserWindow方法里的变量,例如上图,我可以利用#width,#height去控制我要创建的A窗口的宽和高等,这里的webPreferences是不能删除的,因为它的作用是把主进程electron通过预加载传递给渲染进程,如果删除了,在渲染进程中就无法通过window.electron获取electron对象,注意:import引入的路劲因为放到了frame文件夹里面,所以对应的路径也应该跟着改变,如果需要的话也可以去vite.config中去配置短路径,如下图:

image.png

此时就已经封装好了A窗口了,那我们要怎么使用这个封装好的类呢?

2.在主进程main文件夹下的index.ts中使用封装好的窗口

2.1引入AFrame这个类

image.png

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,如下图所示:

image.png

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文件

image.png

写一个类,名字叫做EventRouter,也就是我们的事件路由对象,router故名思意,类似于vue里面的router,代表了所有的路由而route表示的是单个路由,这里我们给EventRouter封装了两个属性,#api与routers=[],与三个方法,第一个方法是addApi(),第二个方法是addRoutesrs,第三个方法是router,分别有什么作用呢?

4.1EventRouter添加对象与使用

如果要分辨是那个渲染进程传值给主进程,我们要通过渲染进程的值去分辨,如何拿到这个值呢,就可以使用EventRouter.addApi方法,拿到渲染进程传给主进程的值,如何使用呢?

4.1.1引入routers

image.png

这里的routers输出结果为:

image.png

这是怎么来的呢?让我们查看router.template.ts,此时可以看到

image.png

在template这个文件里面我们引入了route,并且创建了一个数组名字为routers,接着给这个数组去添加一个eventroute对象,可以理解为将单个的路由添加进去router里面,组合成全部的路由,添加了之后routes这个数组里面就有三个对象所构成,每个对象又包含了一个name和一个回调函数,其中,name为newWinA,newWinB,newWinC,回调函数此时为空,template里面给数组添加的对象中的回调函数,就是最终我们要去调用的函数,那该怎么给这个函数传值并且调用呢?

4.2.1在主进程里先引入

image.png

主窗口进行了封装和调用

image.png

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,就被填充为了

image.png


这里可以理解为将需要传的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)

})

image.png

此时首先会先遍历routers这个数组

image.png

传过来的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窗口:

image.png

把这个添加到api中,

接着修改一下router.template.ts中的方法

image.png

这里我是直接修改了mainWindow为AWindow,当然也可以在这个里面再push一个对象,这样,就可以灵活的修改了,以上就是初级封装主进程了,因为缺少了路由的懒加载。

评论(

您还未登录,请先去登录
表情
查看更多

相关作者

  • 获取点赞0
  • 文章阅读量1

相关文章

暂无相关文章

联系小鹿线

咨询老师

咨询老师

扫码下载APP