# electron-base **Repository Path**: yshx/electron-base ## Basic Information - **Project Name**: electron-base - **Description**: electron实战项目,从零搭建,由浅入深系统学习electron开发。 - **Primary Language**: Unknown - **License**: MIT - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 2 - **Forks**: 1 - **Created**: 2023-04-16 - **Last Updated**: 2025-07-21 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # Electron实战笔记及作业总结 ## 介绍 electron实战项目,从零搭建,由浅入深系统学习electron开发。 ## 安装教程 npm install npm run start ## 安装Electron卡住问题 **安装命令:npm install electron -D** 安装electron时,会默认从github下载依赖,由于网络受限,需要配置国内下载源。 本地项目创建.npmrc文件,添加如下代码: ```js registry=https://registry.npmmirror.com/ ELECTRON_MIRROR="https://npmmirror.com/mirrors/electron/" ``` ## 查看macos系统安装了哪些electron应用 ``` for app in /Applications/*; do;[ -d $app/Contents/Frameworks/Electron\ Framework.framework ] && echo $app; done ``` 结果如下: ![electron应用](doc/electron-apps.png) ## 实现窗口拖动效果 给渲染页面的body元素添加css属性-webkit-app-region:drag; ```css ``` ## 本地启动项目自动打开调试控制台 [具体参考官方文档API](https://www.electronjs.org/zh/docs/latest/api/web-contents#contentsopendevtoolsoptions) ```js app.whenReady().then(() => { window = new BrowserWindow({width: 800, height: 600, titleBarStyle: 'hiddenInset'}) window.loadFile(path.join(__dirname,'../renderer/index.html')) window.webContents.openDevTools() }) ``` ## Electron应用单实例运行 通常,windows系统,双击exe可执行程序会创建多个应用实例,Mac系统上双击会唤起当前运行的应用实例。 如果限制要限制单实例应用,可使用app.requestSingleInstanceLock() 实例运行锁,只有第一个启动的实例返回true,其他启动的实例返回false。 ```js const goTheLock = app.requestSingleInstanceLock() if(!goTheLock) { app.quit() }else { // 其他实例唤起的处理效果 app.on('second-instance', (event,argv)=>{ mainWindow.restore() mainWindow.show() handleSchemeWeakup(argv) }) } ``` ## 应用协议唤起 应用协议就是应用独一无二的一个名称,然后注册到操作系统里面,通过协议名就能唤起软件。 **注册协议** ```js app.setAsDefaultProtocolClient('electron-base') ``` 在浏览器中输入 electron-base:// 之后,会弹出跳转提示,点击同意就能启动并跳转到桌面应用了。 [Mac端自定义协议](https://developer.apple.com/documentation/xcode/defining-a-custom-url-scheme-for-your-app) [Windows端自定义协议](https://learn.microsoft.com/en-us/windows/uwp/launch-resume/launch-app-with-uri) **获取协议参数** Mac端协议唤起,监听[open-url](https://www.electronjs.org/docs/latest/api/app#event-open-url-macos)事件,在ready之前注册该事件。 ```js app.on('open-url', (event, url) => { console.log(url) }) ``` windows端唤起,通过process.argv ```js const url = process.argv.find(v => v.startsWith(scheme)) ``` ## 开启node环境 设置odeIntegration:true。在html页面中可以支持node API,出于安全考虑,官方不建议直接开启node环境。 ```js mainWindow = new BrowserWindow({ width: 800, height: 600, webPreferences: { nodeIntegration: true, // 开启node.js环境,不安全,不建议开启 contextIsolation: false, // 关闭上下文隔离,preload.js与index.html共享window对象等 }, }) ``` ## 运行preload.js 预加载脚本有权限访问node API,可以替代nodeIntegration,由electron注入到index.html中,早于index.html执行。 如果在preload.js中需要操作DOM,则要在html解析完成后操作。访问渲染进程API,需要关闭渲染进程沙箱,sandbox:false。 ```js mainWindow = new BrowserWindow({ webPreferences: { preload:path.join(__dirname,'../preload/preload.js'), // 用preload执行node api sandbox:false // 渲染进程开启沙箱模式,关闭,preload.js可以访问electron 渲染进程API } }) ``` ## 上下文隔离 webPreferences中的选项contextIsolation默认是true,开启上下文隔离,表示preload.js与index.html是不共享document和window等对象。 防止污染全局对象。 ```js const win = new BrowserWindow({ width: 800, height: 600, webPreferences: { contextIsolation: true, // 默认就是 true }, }) ``` 如果需要在preload.js与index.html之间共享变量,建议选择contextbridge ```js const { contextBridge } = require('electron') const path = require('path') const fs = require('fs') // 从预加载脚本将api暴露给渲染器 contextBridge.exposeInMainWorld('electron',{ doSomething:()=>{ return console.log('something')}, saveFile: (filepath,content) => { fs.writeFile(path.join(__dirname,filepath),content,error=>{ console.log(error, "error") }) } }) ``` ## Electron进程通信 electron主要进程有主进程,渲染进程,辅助进程等。 一个electron应用最多有五类进程: | 进程名称 | 含义 | 作用 | | ----------- | ----------- |------------------| | Electron | 主进程 | 控制应用生命周期,子进程管理,控制地址栏/书签栏, 前进/后退按钮等| | Electron Helper | 网络进程 |负责页面网络资源加载 | | Electron Helper(Renderer)| 渲染进程 |负责页面布局绘制 | | Electron Helper(GPU) | GPU进程 |负责GPU渲染 | | Electron Helper(Plugin) | 插件进程 |负责插件运行 | ### 主进程与渲染进程 主进程运行在node.js环境中,负责应用的生命周期,管理渲染进程。 渲染进程获取主进程API结果,有三种通信方式: - sendSync与returnValue,同步调用方式 - send与reply, 异步回调 - invoke与handle,异步promise方式 **sendSync与returnValue** 渲染进程: ```js const val = ipcRenderer.sendSync('isDarkMode') ``` 主进程: ```js const { ipcMain, nativeTheme } = require('electron') ipcMain.on('isDarkMode',(event,args)=>{ event.returnValue = nativeTheme.shouldUseDarkColors }) ``` **send与reply** 渲染进程: ```js const { ipcRenderer } = require('electron') ipcRenderer.send('isDarkMode') ipcRenderer.on('isDarkMode', (event, value) => { console.log('on reply', value) }) ``` 主进程: ```js const { ipcMain, nativeTheme } = require('electron') ipcMain.on('isDarkMode', (event, args) => { event.reply('isDarkMode', nativeTheme.shouldUseDarkColors) }) ``` **invoke与handle(推荐使用)** 渲染进程: ```js const { ipcRenderer } = require('electron') ipcRenderer.invoke('isDarkMode').then((value) => console.log('invoke reply', value)) ``` 主进程: ```js const { ipcMain, nativeTheme } = require('electron') ipcMain.handle('isDarkMode', (event, args) => { return nativeTheme.shouldUseDarkColors }) ``` ## 理解Chrome进程 关闭hrome浏览器重新打开,打开浏览器的任务管理器,查看当前进程(浏览器进程及子进程)。 - 浏览器主进程负责创建和管理浏览器窗口,即浏览器多个窗口共享同一个进程。 - 每个标签页加载网站都会创建独立的渲染进程,即Google Chrome Helper(Renderer)。 ## 理解Electron进程 Electron的主进程负责创建和管理窗口。当调用win.loadURL加载页面时,会创建渲染进程Electron Helper (Renderer)。 **注意:并非每开一个窗口就创建一个进程,而是所有窗口都由 Electron 主进程管理。** 因此:在 Electron 应用中,不创建任何窗口和创建100个窗口,对应用的进程数量没有任何影响。 ## Electron系统菜单 electron应用有四类菜单:窗口菜单,上下文菜单,托盘菜单,Dock菜单(mac系统专属)。 ### 窗口菜单 定义菜单选项: ```js const options = [ { label: '自定义菜单', submenu: [ { label: '子菜单1', click: ()=> { console.log('子菜单1 click') } }, { label: '默认选中', type: 'checkbox', checked: true, }, ] }, { type: 'separator' }, { label: '调试菜单', submenu:[ { role: 'devTools', accelerator: 'Shift+I', click: ()=>{} } ] } ] ``` 创建原生菜单 ```js const { Menu } = require('electron') const menu = Menu.buildFromTemplate(options) ``` 创建窗口菜单,mac系统第一个菜单名与应用名相同,第一个菜单选项需要占位 ```js function initMenu() { const tpl = [...options] if(process.platform==='darwin') { tpl.unshift({label:''}) } const menu = Menu.buildFromTemplate(options) Menu.setApplicationMenu(menu) } ``` [Menu-官方文档](https://www.electronjs.org/zh/docs/latest/api/menu) ### 上下文菜单 调用方法:menu.popup ```js function initContextMenu() { // 2.上下文菜单 const menu = Menu.buildFromTemplate([ { label: '文字加粗', click: ()=> { mainWindow.webContents.send('on-menu','bold') } }, { label: '改变颜色', click: ()=> { mainWindow.webContents.send('on-menu','color') } } ]) menu.popup({ callback:()=>{ console.log('context menu') } }) } ``` ### 托盘菜单 托盘就是任务栏上注册的图标。 在 macOS 下,设置托盘的图片名称必须以 Template 结尾,一般需要提供 16x16(72dpi) 和 32x32@2x(144dpi) 的两个图片。例如: - trayTemplate.png - trayTemplate@2x.png 在Window 下,图标名称不用Template结尾,但是最好使用ico格式的图片效果更好。 托盘菜单API: - tray.setContextMenu:设置托盘菜单 - tray.setToolTip:托盘的悬浮提示 - tray.on():监听托盘事件 ```js let tray = null function initTray() { tray = new Tray(path.join(__dirname,'logoTemplate.png')) const menu = Menu.buildFromTemplate(options) tray.setToolTip('electron-base') tray.setContextMenu(menu) tray.on('click',()=>{ console.log('tray click') }) } ``` [Tray-官方文档](https://www.electronjs.org/zh/docs/latest/api/tray) ### Dock菜单(Mac专属) ```js function initDockMenu() { // mac系统设置dock菜单 if(process.platform === 'darwin') { const { dock } = app const menu = Menu.buildFromTemplate(options) dock.setMenu(menu) } } ``` ## Electron之Webview ## Electron之对话框 ## Electron之快捷键 ## Electron之剪贴板 ## Electron会话管理