文章目录
- 一、使用electron-vite新建项目
- 二、目录结构
- 三、渲染进程调用主进程
- 1、方式一 —— 允许有返回值
- · src/main/index.js
- · src/preload/index.js
- · src/renderer/index.html
- 2、方式二—— 允许有返回值 (推荐写法)
- · src/main/index.js
- · src/preload/index.js
- · src/renderer/index.html
- 3、方式三 —— 无返回值,不等待响应
- · src/main/index.js
- · src/preload/index.js
- · src/renderer/index.html
- 四、主进程触发渲染进程
- · src/main/index.js
- · src/preload/index.js
- · src/renderer/index.html
- 五、功能介绍
- 1、透明窗口设置
- 2、系统截图功能
- 3、系统托盘图标及闪烁功能
- 六、问题处理
- 1、图标打包路径无法获取问题
- · 修改图标路径获取
- 2、允许更改安装目录
- · package.json 配置
- 3、loadFile添加参数
- 4、http数据请求与cookie设置
- 5、iframe CSP
- 6、多页面打包
- · electron.vite.config.mjs
- 7、路由切换主进程代码多次执行
- 七、npm库
- References
一、使用electron-vite新建项目
- 1、npm命令
npm create @quick-start/electron
- 2、yarn命令
yarn create @quick-start/electron
- 3、electron镜像地址:
electron_mirror=https://npmmirror.com/mirrors/electron/
electron_builder_binaries_mirror=https://npmmirror.com/mirrors/electron-builder-binaries/
- 4、填写项目名称
? Project name: electron-vue-app
- 5、选择vue框架:
? Select a framework: vanilla
> vuereactsveltesolid
- 6、其他配置项
? Add TypeScript? » No / Yes
Yes
? Add Electron updater plugin? » No / Yes
Yes
? Enable Electron download mirror proxy? » No / Yes
Yes
二、目录结构
├─ /.vscode
├─ /build
├─ /node_modules
├─ /out # 运行时的输出目录
├─ /resources # 主进程和预加载脚本资源文件目录
├─ /src
| ├─ /main # Electron主进程
| ├─ /preload # Electron预加载脚本
| └─ /renderer # Electron渲染进程, vue常规目录结构
| | ├─ /assets
| | ├─ /components
| | ├─ /views
| | ├─ App.vue
| | ├─ main.js
| | └─ index.html
├─ .editorconfig
├─ .eslintignore
├─ .eslintrc.cjs
├─ .gitignore
├─ .npmrc
├─ .prettierignore
├─ .prettierrc.yaml
├─ dev-app-update.yml
├─ electron-builder.yml
├─ electron.vite.config.mjs
├─ package.json
├─ README.md
三、渲染进程调用主进程
1、方式一 —— 允许有返回值
· src/main/index.js
import { app, ipcMain, BrowserWindow } from 'electron'
app.whenReady().then(() => {// ...new BrowserWindow({width: 800,height: 600,// 其他窗口配置...})ipcMain.handle('renderderCallMain', async (event, value) => {console.log('renderder call main...', value)})// ...
})
· src/preload/index.js
import { contextBridge } from 'electron'
import { electronAPI } from '@electron-toolkit/preload'
if (process.contextIsolated) {try {contextBridge.exposeInMainWorld('electron', electronAPI)} catch (error) {console.error(error)}
} else {window.electron = electronAPI
}
· src/renderer/index.html
window.electron.ipcRenderer.invoke('renderderCallMain', 'hello world!')
2、方式二—— 允许有返回值 (推荐写法)
· src/main/index.js
import { app, ipcMain, BrowserWindow } from 'electron'
app.whenReady().then(() => {// ...new BrowserWindow({width: 800,height: 600,// 其他窗口配置...})ipcMain.handle('renderderCallMain', async (event, value) => {console.log('renderder call main...', value)})// ...
})
· src/preload/index.js
import { contextBridge, ipcRenderer } from 'electron'const call = {renderderCallMain: (value) => ipcRenderer.invoke('renderderCallMain', value),
}if (process.contextIsolated) {try {contextBridge.exposeInMainWorld('call', call)} catch (error) {console.error(error)}
} else {window.call = call
}
· src/renderer/index.html
window.call.renderderCallMain('hello world!')
3、方式三 —— 无返回值,不等待响应
· src/main/index.js
import { app, ipcMain, BrowserWindow } from 'electron'
app.whenReady().then(() => {// ...new BrowserWindow({width: 800,height: 600,// 其他窗口配置...})ipcMain.on('ping', () => console.log('pong'))// ...
}
· src/preload/index.js
import { contextBridge, ipcRenderer } from 'electron'const call = {ping: () => ipcRenderer.send('ping'),
}if (process.contextIsolated) {try {contextBridge.exposeInMainWorld('call', call)} catch (error) {console.error(error)}
} else {window.call = call
}
· src/renderer/index.html
window.call.ping()
四、主进程触发渲染进程
· src/main/index.js
import { app, globalShortcut, BrowserWindow } from 'electron'
app.whenReady().then(() => {// ...const mainWindow = new BrowserWindow({width: 800,height: 600,// 其他窗口配置...})globalShortcut.register('CommandOrControl+S', () => {mainWindow.webContents.send('commandOrControlS', 'command or control + s...')})// ...
})
· src/preload/index.js
import { contextBridge, ipcRenderer } from 'electron'
const listen = {commandOrControlS: (callback) => ipcRenderer.on('commandOrControlS', async (event, value) => callback(value)),
}if (process.contextIsolated) {try {contextBridge.exposeInMainWorld('listen', listen)} catch (error) {console.error(error)}
} else {window.listen = listen
}
· src/renderer/index.html
window.listen.commandOrControlS((value) => {console.log(value)
})
五、功能介绍
1、透明窗口设置
const mainWindow = new BrowserWindow({width: 80,height: 162,frame: false, // 透明窗口transparent: true, // 透明窗口backgroundColor: '#00000000', // 透明窗口autoHideMenuBar: true, // 透明窗口
})
2、系统截图功能
import { desktopCapturer } from 'electron'async function desktopCapturerHandle() {const sources = await desktopCapturer.getSources({types: ['window'],thumbnailSize: {width: 1920,height: 1080,},})return sources[0]?.thumbnail.toDataURL('image/png'),
}
3、系统托盘图标及闪烁功能
import { app, BrowserWindow, Tray, Menu } from 'electron'let flickerTimer = nullapp.whenReady().then(() => {// ...const mainWindow = new BrowserWindow({width: 800,height: 600,// 其他窗口配置...})const tray = new Tray('./icon.ico')const contextMenu = Menu.buildFromTemplate([{ label: '显示 ', click: () => {mainWindow.show()stopTray(tray)}},{ type: 'separator' },{ label: '退出 ', click: () => {mainWindow.off('close', closeHandle)app.quit()}},])tray.setContextMenu(contextMenu)tray.on('double-click', function() {mainWindow.show() // 点击图标时恢复窗口stopTray(tray)})tray.on('click', function() {if (flickerTimer) {mainWindow.show() // 点击图标时恢复窗口stopTray(tray)}})// ...
})function flickerTray(tray) {if (!flickerTimer) {let hasIco = falseflickerTimer = setInterval(() => {// 图标与透明图标切换以实现闪烁功能tray.setImage(hasIco ? './icon.ico' : './empty.ico')hasIco = !hasIco}, 500)}
}function stopTray(tray) {if (flickerTimer) {clearInterval(flickerTimer)flickerTimer = null}tray.setImage('./icon.ico')
}
六、问题处理
1、图标打包路径无法获取问题
· 修改图标路径获取
import { app } from 'electron'
const path = require('path')function resolvePath() {const publicPath = 'build'const fileName = 'icon.ico'if (process.env.NODE_ENV === 'development') {return './' + publicPath + '/' + fileName}return path.join(path.dirname(app.getPath('exe')), '/resources/' + publicPath + '/' + 'fileName')
}
· package.json 配置图标打包
{..."build": {"extraResources": [{"from": "./build","to": "./build"}]}...
}
图标大小需 256x256
,格式为ico
2、允许更改安装目录
· package.json 配置
{..."build": {"nsis": {"allowToChangeInstallationDirectory": true, // 允许更改安装目录"installerIcon": "./build/icon.ico", // 安装图标"uninstallerIcon": "./build/icon.ico", // 卸载图标"installerHeaderIcon": "./build/icon.ico", // 安装程序头部图标"createDesktopShortcut": true, // 创建桌面快捷方式"createStartMenuShortcut": false, // 加入开始菜单}}...
}
3、loadFile添加参数
import { app, BrowserWindow } from 'electron'
import { join } from 'path'app.whenReady().then(() => {// ...const mainWindow = new BrowserWindow({width: 800,height: 600,// 其他窗口配置...})mainWindow.loadFile(join(__dirname, '../renderer/index.html'), {search: 'id=test',})// ...
})
4、http数据请求与cookie设置
- 1)、由于
fill://
协议无法设置cookie,所以请求只能在主进程发起 - 2)、使用Chromium的原生网络库发出HTTP / HTTPS请求 或 Node.js的HTTP 和 HTTPS 模块
const { app } = require('electron')app.whenReady().then(() => {const { net } = require('electron')const request = net.request('https://github.com')request.on('response', (response) => {console.log(response)response.on('data', (chunk) => {console.log('BODY: ' + chunk)})response.on('end', () => {console.log('No more data in response.')})})request.end()
})
- 3)、从请求结果中
set-cookie
获取cookie并返回给渲染端进行存储
5、iframe CSP
<meta http-equiv="Content-Security-Policy"content="script-src 'self' https://example.com; img-src https://example.com"
/>
修改html中的meta属性,这将允许在iframe中加载来自 self
和 example.com
域的脚本,并允许加载来自 example.com
域的图像
6、多页面打包
· electron.vite.config.mjs
export default defineConfig({renderer: {build: {rollupOptions: {input: {index: './src/renderer/index.html',other: './src/renderer/other.html',}}}}
})
7、路由切换主进程代码多次执行
检查 ipcRenderer.on()
路由切换后是否多次在 onMounted 注册
,需在 onBeforeUnmount
中及时调用主进程 ipcRenderer.removeListener()
注销事件的监听
七、npm库
- 1、
"@jitsi/robotjs": "^0.6.11"
适用于自动化工具,有控制I/O、系统截图等功能 - 2、
"tesseract.js": "^5.0.5"
基于js的图像识别 - 3、
"jimp": "^0.22.12"
图像处理工具,有图片裁剪、保存、图片大小更改等功能 - 4、
"nodemailer": "^6.9.13"
基于node的邮件发送工具
References
[1] Electron文档
[2] 基于electron-vite构建Vue桌面客户端