通过学习electron了解一下做项目中好奇的问题,我觉得下面这张图就可以说明一切了,就是在初次创建并显示主窗口后,一切都将建立在渲染进程和主进程的通信上,而用的技术就是ipcMain和ipcRender,那么渲染进程如何与主进程建立连接的桥梁,就涉及contextBridge,然后通过exposeInMainWorld()将API注入到window,就可全局访问。
因为已经写过截图和富文本编辑功能了,等后期再做这类的文章总结,主要目前时间不够,所以慢慢来吧。
标题electron工作流程
主进程:
可以看作是package.json中的main属性对应文件
一个应用只会有一个主进程
只有主进程可以进行GUI的API操作
渲染进程:
windows中展示的界面通过渲染进程表现
一个应用可以有多个渲染进程
整体流程:
启动主进程,创建窗口
加载指定界面
开启渲染进程,若渲染进程要进行通讯就需要IPC来完成进程间的操作
electron环境搭建
electron + react搭建的框架已经搭建完成来,所以省略搭建的总结文章,可以直接github上拿代码。
标题electron 加载app
启动app
app.whenReady().then(() => {
// 创建window
const mainWin = new BroBrowserWindow({})
// loadFile加载指定的界面显示
mainWin.loadFile('')
mainWin.on('close|hide|move|minimize')
})
app.on('window-all-close', () => { ... })
标题electron生命周期
ready: app初始化完成
dom-ready: 一个窗口中的文本加载完成
did-finish-load:导航完成时触发
window-all-closed:所有窗口都被关闭时触发
before-quit:在关闭窗口之前触发
will-quit:在窗口关闭并且应用退出时触发
quit:当所有窗口被关闭时触发
closed:当窗口关闭时触发,此时应删除窗口引用
标题electron BrowserWindow参数修改
官网此API地址
mainWindow = new BrowserWindow({
show: false,
width: 1024,
height: 728,
// min|max -width|height来设置窗口的最大值或最小值
minWidth: 700,
minHeight: 570,
// icon:作用在window窗口左上角的小logo,mac不显示,linux暂不清楚,支持png、jpg、ico格式
icon: getAssetPath('logo.png'),
// title:窗口标题作用在window和mac上,linux暂不清楚
title: "横截面",
// frame:默认为true,设置为false就是将默认的菜单栏menu隐藏,可以自定义menu
frame: false,
// transparent: true, // 窗口透明 默认false. 在Windows上,仅在无边框窗口下起作用。
// // 自动隐藏菜单栏,除非按了Alt键。 默认值为 false.
// autoHideMenuBar: true,
webPreferences: {
preload: app.isPackaged
? path.join(__dirname, 'preload.js')
: path.join(__dirname, '../.erb/dll/preload.js'),
},
});
mainWindow.loadURL(resolveHtmlPath(''));
要是在主窗口想和渲染窗口进行交互,则通过ipcMain和ipcRender来实现新窗口
ipcMain: 从主进程到渲染进程的异步通信。
ipcRender:是一个 EventEmitter 的实例。 当在主进程中使用时,它处理从渲染器进程(网页)发送出来的异步和同步信息。 从渲染器进程发送的消息将被发送到该模块。
标题electron 创建子窗口
// 引入
import { createAt } from './views/at'
createAt(mainWindow)
import { BrowserWindow } from "electron"
import { getAssetPath } from '../utils/path'
export const createAt = (main: BrowserWindow) => {
const createAtWindow = new BrowserWindow({
show: false,
width: 1024,
height: 728,
title: '@窗口',
minWidth: 700,
minHeight: 570,
icon: getAssetPath('logo.png'),
})
// 当主窗口加载好了,再显示at窗口
main.on('ready-to-show', () => {
if (process.env.START_MINIMIZED) {
createAtWindow.minimize();
} else {
createAtWindow.show();
}
})
}
标题electron 阻止窗口关闭
macos系统通知设置了,但并未显示,这块儿还得进行调整
标题electron 自定义托盘样式
/**
* 给程序增加托盘样式图标
*/
app.on('ready', () => {
let appIcon = new Tray(path.join(__dirname, '../assets/tray.png'))
const contextMenu = Menu.buildFromTemplate([
{ label: '退出', accelerator: 'Cmd+Q', click: () => { app.exit() } }
])
appIcon.setContextMenu(contextMenu)
})
标题electron 托盘及菜单
托盘这块儿,主要要学习的就是右击显示菜单,点击将主屏幕显示在最上面的窗口上
/** 托盘文件内容 **/
import { BrowserWindow, Menu, Tray, app, nativeImage } from "electron";
import { getAssetPath } from "../utils/path";
// 托盘小图标
const applicationImage = (path: any) =>
nativeImage.createFromPath(path).resize({ width: 18, height: 18 });
// 获取图标路径
const trayIcon = getAssetPath('tray.png');
export const createTray = (main: BrowserWindow) => {
/** 根据托盘所需的大小重绘 */
let tray = new Tray(applicationImage(trayIcon))
const menuOption = [
{ label: '退出', accelerator: 'Cmd+Q', click: () => { app.exit() } }
]
const contextMenu = Menu.buildFromTemplate(menuOption)
/** 使用setContextMenu要慎重,因为这是设置默认行为的,要是右击,需要使用popUpContextMenu */
// tray.setContextMenu(contextMenu);
/**
* 点击,显示主窗口
*/
tray.on('click', () => {
if(!main.isDestroyed()) main.show();
})
/**
* 右击,显示菜单
*/
tray.on('right-click', (e) => {
tray.popUpContextMenu(contextMenu)
})
}
标题electron的dialog
主进程
import { app, BrowserWindow, shell, ipcMain, Notification, dialog} from 'electron';
/**
* 下载
*/
ipcMain.on(MainEnums.DOWNLOAD, () => {
dialog.showOpenDialog({
title: '请选择下载路径',
defaultPath: app.getPath('downloads'),
properties: ['openDirectory', 'createDirectory']
}).then((res) => {
if(res.filePaths) {
store.set('downloadPath', res.filePaths)
}
})
})
/**
* 调用下载
*/
ipcRenderer.send(MainEnums.DOWNLOAD)
标题electron app dock使用
main.ts文件中的app使用dock
/**
* Add event listeners...
*/
if(isMac) {
const dockIcon = applicationImage({path: 'dockIcon.png'})
// 获取图标路径
app.dock.setIcon(dockIcon)
}
main.ts文件中所使用的applicationImage封装方法,我写在utils/path.ts内:
const RESOURCES_PATH = app.isPackaged
? path.join(process.resourcesPath, 'assets')
: path.join(__dirname, '../../assets');
export const getAssetPath = (...paths: string[]): string => {
return path.join(RESOURCES_PATH, ...paths);
};
// dock图标和托盘小图标共用
export const applicationImage = ({path, size}: PathType['image']) =>{
return nativeImage.createFromPath(getAssetPath(path)).resize({ ...size })
};
electron配置打包:
参考:https://juejin.cn/post/7009179524520738824
持续更新中。。。