Electron中类事件监听时this.mainWindow未定义的问题求助
解决Electron类中事件回调里
this指向丢失的问题 这个问题我太熟悉了——本质就是JavaScript的this绑定机制踩坑:当你把类的方法直接作为事件回调传递时,回调执行时的this会指向触发事件的对象(比如Tray实例或者BrowserWindow实例),而不是你的AppManager类实例,自然就访问不到this.mainWindow和this.isQuitting了。
下面是具体的修复方案,分三个关键修改点:
1. 给事件回调绑定类实例的this
在createWindow方法里,给tray的click事件和mainWindow的close事件绑定当前类实例的this,确保回调执行时this指向AppManager:
// 原写法 this.tray.on('click', this.onClick) this.mainWindow.on('close', this.onClose) // 修改后 this.tray.on('click', this.onClick.bind(this)) this.mainWindow.on('close', this.onClose.bind(this))
2. 修复上下文菜单中的this指向
上下文菜单里的click回调用了普通函数,this会指向菜单选项对象,改成箭头函数就能继承外层createWindow方法里的this(也就是AppManager实例):
// 原上下文菜单模板 this.contextMenu = Menu.buildFromTemplate([ { label: 'Show App', click: function () { this.mainWindow.show() } }, { label: 'Quit', click: function () { this.isQuiting = true this.app.quit() } } ]) // 修改为箭头函数 this.contextMenu = Menu.buildFromTemplate([ { label: 'Show App', click: () => { this.mainWindow.show() } }, { label: 'Quit', click: () => { this.isQuitting = true; this.app.quit() } } ])
3. 修正onActivate方法的属性访问错误
onActivate里你写的this.app.mainWindow是错误的,mainWindow是AppManager类的属性,应该用this.mainWindow:
// 原写法 if (this.app.mainWindow === null) { this.createWindow() } // 修改后 if (this.mainWindow === null) { this.createWindow() }
完整修正后的代码片段
class AppManager { constructor (app, options) { this.app = app this.options = options || {} // 修复原代码中强制覆盖传入options的问题 this.bindEvents() } bindEvents () { this.app.on('ready', this.onReady.bind(this)) this.app.on('window-all-closed', this.onWindowAllClosed.bind(this)) this.app.on('activate', this.onActivate.bind(this)) } onReady () { this.createWindow() } onWindowAllClosed () { if (process.platform !== 'darwin') { this.app.quit() } } onActivate () { if (this.mainWindow === null) { this.createWindow() } } onClose (e) { if (this.isQuitting) { this.mainWindow = null } else { e.preventDefault() this.mainWindow.hide() } } onClick () { this.mainWindow.show() } createWindow () { this.isQuitting = false this.contextMenu = Menu.buildFromTemplate([ { label: 'Show App', click: () => { this.mainWindow.show() } }, { label: 'Quit', click: () => { this.isQuitting = true; this.app.quit() } } ]) this.tray = new Tray('./public/images/icon.ico') this.tray.setContextMenu(this.contextMenu) this.tray.on('click', this.onClick.bind(this)) this.mainWindow = new BrowserWindow(this.options) this.mainWindow.loadURL(url.format({ pathname: path.join(__dirname, '../../../public/index.html'), protocol: 'file:', slashes: true })) this.mainWindow.tray = this.tray this.mainWindow.on('close', this.onClose.bind(this)) } }
额外补充个小细节:原constructor里的this.options = options = {}会强制把传入的options参数设为空对象,改成this.options = options || {}可以保留用户传入的配置,更合理。
这样修改后,所有事件回调里的this都会稳定指向AppManager的实例,就能正常访问this.mainWindow和this.isQuitting了。
内容的提问来源于stack exchange,提问作者Ty Everett
相关产品推荐
相关产品推荐

