以类的形式封装只是演示,只是一种思路,并非在后续会使用,但是大家可以参考在自己的项目中使用。这里面有一些坑,我会告诉你,我其实也尝试过 TypeScript 的方式,最终还是败给了错误。假如你想要使用 class 封装,那么一定要注意生命周期。
安装一些常用库
npm install electron-util camelcase --save
electron-util 里面封装了常用的帮助库
camelcase 是用来转事件名的,改成驼峰式命名
这里告诉大家 快速搜索包的一个小技巧,下载 chrome 右键搜插件,自行添加 npm 搜索设置然后就可以选中包明进行快速搜索。
添加事件映射
添加 main/events.js
export default [
'accessibility-support-changed',
'activate',
'activity-was-continued',
'before-quit',
'browser-window-blur',
'browser-window-created',
'browser-window-focus',
'certificate-error',
'continue-activity',
'gpu-process-crashed',
'login',
'new-window-for-tab',
'open-file',
'open-url',
'quit',
'ready',
'select-client-certificate',
'update-activity-state',
'web-contents-created',
'will-continue-activity',
'will-finish-launching',
'will-quit',
'window-all-closed'
]
里面存放的是所有需要转换到 app 上面的事件,等会我们会让它们自动做绑定。
Application.js
导入依赖
import electron from 'electron'
import util from 'electron-util'
import camelcase from 'camelcase'
import events from './events'
构造函数里面第一个要准备的是 ready 事件,只有当这个事件都完成的时候,才能继续做一些事情,假如你想直接把 electron
上面的东西通过 Object.assign
拷贝到 this 上面,会报错,因为没有准备好,能拷贝某些模块也会报错。 electron 上面的属性其实是一些 getter
。
绑定 ready 的时候不要忘记绑定 this,要不然 this 会丢失,这是 js 的陷阱之一。
class Application {
constructor() {
electron.app.on('ready', this.ready.bind(this))
}
}
然后在 ready 里面创建窗口和初始化事件绑定
async ready() {
Object.assign(this, electron)
this.mainWindow = this.createMainWindow()
this.initEvent()
}
创建窗口,要做一些兼容,使用 util 会简洁不少,比如判断环境载入不同的开始文件。
createMainWindow(opts) {
const win = new electron.BrowserWindow(opts)
if (util.is.development) {
win.webContents.openDevTools()
win.loadURL(`http://localhost:${process.env.ELECTRON_WEBPACK_WDS_PORT}`)
} else {
util.loadFile(win, 'index.html')
}
win.on('close', () => {
this.mainWindow = null
})
win.webContents.on('devtools-opened', () => {
win.focus()
setImmediate(() => win.focus())
})
return win
}
初始化事件,假如自身没有这个方法的时候不要绑定,要不然绑个 undefined 会报错
initEvent() {
events.forEach(name => {
if (this[camelcase(name)]) {
this.app.on(name, this[camelcase(name)].bind(this))
}
})
}
添加个平台兼容事件,这两个是事件,在 initEvent 里面会自动绑定。
windowAllClosed() {
if (util.is.macos) {
electron.app.quit()
}
}
activate() {
if (!this.mainWindow) {
this.mainWindow = this.createMainWindow()
}
}
这样我们就实现了一个约定优先的 Electron 开发框架,只要你封装的够好,完全可以实现一个快速开发框架。
入口文件
修改 main/index.js
, 够刚刚的类进行实例化。
import Application from './Application'
let app = new Application()
避免循环依赖
在编程中,对于初学者最头疼的可能就是循环依赖了,假如你有一个 Tray.js 来控制通知栏的一些逻辑,建议在 ready 里面实例化,并把this
传递进去,这样不仅可以避免循环依赖,还可以避免有些逻辑没有准备好,导致的错误。
import Tray from './tray'
async ready() {
this.tray = new Tray(this)
}
另外一种方式就是属性注入。
let app = new Application()
electron.app.on('ready', () => {
app.tray = new Tray()
app.tray.app = app
})
或者使用一个依赖管理中心
const depHub = {}
let app = new Application(depHub)
electron.app.on('ready', () => {
let tray = new Tray(depHub)
depHub.app = app
depHub.tray = tray
})