electron开发基础

227 阅读3分钟

这是我参与11月更文挑战的第2天,活动详情查看:2021最后一次更文挑战

主要在于目前开发的项目是electron+vue的技术,项目进度过半,但是开发的无比艰辛。难点解决不了,但是一些基础的东西还是有很深理解的。

窗口通信

electron项目中各窗口之间有多种通信方式,这里介绍其中一种ipcMain/ipcRenderer方式。

// A窗口,多为在方法里触发 
createGroup() { 
    ipcRenderer.send("add", "234"); 
} 

// background.js 
ipcMain.on("add", (event, arg) => { 
    win.webContents.send("addReply", arg) 
}) 

// B窗口,在生命周期中接收 
created() { 
    ipcRenderer.on("addReply", (event, arg) => { 
        console.log(arg); 
    }); 
}

但是在项目中出现了一种情况:on方式监听所触发的事件会有多次触发的情况!!! 在网上百度了很久,查到的结果都是将on改成once。但是我修改了以后还是多次触发的情况,希望有大佬看到的话,能帮忙解答下

窗口拖拽

遇到两种情况:

  • 窗口设置movable属性为true;
  • frame为false时候添加拖动样式

设置拖拽属性

win = new BrowserWindow({
  ...
  movable: true,
  ...
})

设置拖拽样式

主窗口设置 frame: false,后,整个窗口不可拖动,因为其关闭了window自带的关闭等功能以及工具栏。可以通过修改修改样式元素方式使元素可以拖动。

.ele_drag {
    -webkit-app-region: drag; /* 让元素可拖动,设置了drag的元素不可点击 */
}
.no_drag {
    -webkit-app-region: no-drag; /* 设置了drag的元素将不可点击,故设置no-drag,让元素可点击 */
}
  • drag一般设置给顶层header元素,使得header部分点击可拖动,但设置了以后会导致header内部元素不可点击,所以需要给可点击元素添加no-drag样式
  • no-drag设置给可点击元素

系统托盘

import {Tray, Menu, nativeImage} from 'electron'
// 托盘图标路径处理
const icon = nativeImage.createFromPath(
    path.join(__static, './favicon.ico')
)
tray = new Tray(icon)
tray.setToolTip('electron demo is running')
tray.setTitle('electron demo')
tray.on('right-click', () => {
    // 右键菜单模板
    const tempate = [
        {
            label: '退出',
            click: () => app.quit(),
        },
    ]
    //通过 Menu 创建菜单
    const menuConfig = Menu.buildFromTemplate(tempate)
    // 让我们的写的托盘右键的菜单替代原来的
    tray.popUpContextMenu(menuConfig)
})
tray.on('click', () => {
    // 这里来控制窗口的显示和隐藏
    if (win.isVisible()) {
        win.hide()
    } else {
        win.show()
    }
})

窗口创建配置

基础配置

import {BrowserWindow} from 'electron'
let win = new BrowserWindow({
    width: 450,  // 窗口宽度
    height: 435, // 窗口高度
    frame: false, // 窗口是否带边框(工具信息)
    movable: true, // 窗口是否可移动
    webPreferences: {
        nodeIntegration: true,
        contextIsolation: false,
        enableRemoteModule: true  // 是否启用remote模块
    }
})

加载配置

if (process.env.WEBPACK_DEV_SERVER_URL) {
    await win.loadURL(process.env.WEBPACK_DEV_SERVER_URL)
    // calendarWin.loadURL(winURL + '/Friendinformation')  // 子窗口
    if (!process.env.IS_TEST) win.webContents.openDevTools() // 开启窗口开发调试工具
} else {
    createProtocol('app')
    win.loadURL('app://./index.html')
    // calendarWin.loadURL('app://./index.html#Friendinformation') // 子窗口
}

窗口的大小切换

remote方式

import {remote} from 'electron'
// 缩小
remote.getCurrentWindow().minimize();
// 放大
remote.getCurrentWindow().maximize();
// 判断是否处于最大化
remote.getCurrentWindow().isMaximized()
// 恢复
remote.getCurrentWindow().restore();

主进程控制

// 缩小
mainWindow.minimize();
// 放大
mainWindow.maximize();
// 判断是否处于最大化
mainWindow.isMaximized();
// 恢复
mainWindow.restore();

二级窗口关闭

通过elecctron的remote模块,可以获取到当前窗口的实例对象,从而执行close方法

import { remote } from "electron";
closeWin() {
  remote.getCurrentWindow().close();
}

主窗口关闭

由于设置了主窗口关闭不退出而是隐藏在系统托盘,所以执行的是窗口实例对象的hide方法

// vue文件中
import { ipcRenderer} from "electron";
hideWin() {
  ipcRenderer.send("hide")
// background.js
ipcMain.on("hide",()=>win.hide())

也可以采用remote模块的方式执行hide方法

import { remote } from "electron";
hideWin() {
  remote.getCurrentWindow().hide();
}

主窗口退出

退出方法有几种:window.close()、window.destory()、app.quit()、app.exit()

  • window.close():尝试关闭窗口

  • window.destory():强制关闭窗口

  • app.quit():如果所有窗口已关闭,直接触发quit事件。

    • 否则会先触发befrore-quit,再关闭所有窗口,最后触发will-quit事件。
    • 在before-quit、will-quit中调用event.preventDefault();在window.close()的回调函数中组织窗口关闭,都可以使得退出失败
  • app.exit():直接退出窗口,没有任何其他操作