以类的形式封装只是演示,只是一种思路,并非在后续会使用,但是大家可以参考在自己的项目中使用。这里面有一些坑,我会告诉你,我其实也尝试过 TypeScript 的方式,最终还是败给了错误。假如你想要使用 class 封装,那么一定要注意生命周期。

安装一些常用库

  1. npm install electron-util camelcase --save
  • electron-util 里面封装了常用的帮助库

  • camelcase 是用来转事件名的,改成驼峰式命名

这里告诉大家  快速搜索包的一个小技巧,下载 chrome 右键搜插件,自行添加 npm 搜索设置然后就可以选中包明进行快速搜索。

添加事件映射

添加 main/events.js

  1. export default [
  2. 'accessibility-support-changed',
  3. 'activate',
  4. 'activity-was-continued',
  5. 'before-quit',
  6. 'browser-window-blur',
  7. 'browser-window-created',
  8. 'browser-window-focus',
  9. 'certificate-error',
  10. 'continue-activity',
  11. 'gpu-process-crashed',
  12. 'login',
  13. 'new-window-for-tab',
  14. 'open-file',
  15. 'open-url',
  16. 'quit',
  17. 'ready',
  18. 'select-client-certificate',
  19. 'update-activity-state',
  20. 'web-contents-created',
  21. 'will-continue-activity',
  22. 'will-finish-launching',
  23. 'will-quit',
  24. 'window-all-closed'
  25. ]

里面存放的是所有需要转换到 app 上面的事件代码封装 - 图1,等会我们会让它们自动做绑定。

Application.js

导入依赖

  1. import electron from 'electron'
  2. import util from 'electron-util'
  3. import camelcase from 'camelcase'
  4. import events from './events'

构造函数里面第一个要准备的是 ready 事件,只有当这个事件都完成的时候,才能继续做一些事情,假如你想直接把 electron 上面的东西通过 Object.assign 拷贝到 this 上面,会报错,因为没有准备好,能拷贝某些模块也会报错。 electron 上面的属性其实是一些 getter

绑定 ready 的时候不要忘记绑定 this,要不然 this 会丢失,这是 js 的陷阱之一。

  1. class Application {
  2. constructor() {
  3. electron.app.on('ready', this.ready.bind(this))
  4. }
  5. }

然后在 ready 里面创建窗口和初始化事件绑定

  1. async ready() {
  2. Object.assign(this, electron)
  3. this.mainWindow = this.createMainWindow()
  4. this.initEvent()
  5. }

创建窗口,要做一些兼容,使用 util 会简洁不少,比如判断环境载入不同的开始文件。

  1. createMainWindow(opts) {
  2. const win = new electron.BrowserWindow(opts)
  3. if (util.is.development) {
  4. win.webContents.openDevTools()
  5. win.loadURL(`http://localhost:${process.env.ELECTRON_WEBPACK_WDS_PORT}`)
  6. } else {
  7. util.loadFile(win, 'index.html')
  8. }
  9. win.on('close', () => {
  10. this.mainWindow = null
  11. })
  12. win.webContents.on('devtools-opened', () => {
  13. win.focus()
  14. setImmediate(() => win.focus())
  15. })
  16. return win
  17. }

初始化事件,假如自身没有这个方法的时候不要绑定,要不然绑个 undefined 会报错

  1. initEvent() {
  2. events.forEach(name => {
  3. if (this[camelcase(name)]) {
  4. this.app.on(name, this[camelcase(name)].bind(this))
  5. }
  6. })
  7. }

添加个平台兼容事件,这两个是事件,在 initEvent 里面会自动绑定。

  1. windowAllClosed() {
  2. if (util.is.macos) {
  3. electron.app.quit()
  4. }
  5. }
  6. activate() {
  7. if (!this.mainWindow) {
  8. this.mainWindow = this.createMainWindow()
  9. }
  10. }

这样我们就实现了一个约定优先的 Electron 开发框架,只要你封装的够好,完全可以实现一个快速开发框架。

入口文件

修改 main/index.js, 够刚刚的类进行实例化。

  1. import Application from './Application'
  2. let app = new Application()

避免循环依赖

在编程中,对于初学者最头疼的可能就是循环依赖了,假如你有一个 Tray.js 来控制通知栏的一些逻辑,建议在 ready 里面实例化,并把this传递进去,这样不仅可以避免循环依赖,还可以避免有些逻辑没有准备好,导致的错误。

  1. import Tray from './tray'
  2. async ready() {
  3. this.tray = new Tray(this)
  4. }

另外一种方式就是属性注入。

  1. let app = new Application()
  2. electron.app.on('ready', () => {
  3. app.tray = new Tray()
  4. app.tray.app = app
  5. })

或者使用一个依赖管理中心

  1. const depHub = {}
  2. let app = new Application(depHub)
  3. electron.app.on('ready', () => {
  4. let tray = new Tray(depHub)
  5. depHub.app = app
  6. depHub.tray = tray
  7. })

代码在这里代码封装 - 图2