Electron笔记
创建集成Vue的Electron项目
方案一: electron-vue 模板项目
方案二: 使用vue-cli创建
- 执行以下命令创建项目
vue create my-electron-app
- 添加electron-builder插件
vue add electron-builder
相关必要配置项
package.json中的main要配置为background.js
Node相关
针对特定进程的控制流
通过检查 Node.js 的
process.platform变量,您可以针对特定平台运行特定代码。 请注意,Electron 目前只支持三个平台:win32(Windows),linux(Linux) 和darwin(macOS) 。
应用生命周期事件
- app.on('ready', callback):当 Electron 完成初始化并准备创建浏览器窗口时触发。
- app.on('window-all-closed', callback):当所有窗口都被关闭时触发。
- app.on('activate', callback):在 macOS 上,当应用图标被点击而没有打开的窗口时触发。
- app.on('browser-window-created', callback):当新的浏览器窗口被创建时触发。
BrowserWindow 类
BrowserWindow类用于创建和管理应用窗口,是 Electron 中最重要的类之一。
const { BrowserWindow } = require('electron');
const mainWindow = new BrowserWindow([options])
options选项:
| 选项 | 类型 | 描述 |
|---|---|---|
| width | number | 窗口宽度(像素) |
| height | number | 窗口高度(像素) |
| x | number | 窗口 x 坐标 |
| y | number | 窗口 y 坐标 |
| minWidth | number | 窗口最小宽度 |
| minHeight | number | 窗口最小高度 |
| maxWidth | number | 窗口最大宽度 |
| maxHeight | number | 窗口最大高度 |
| title | string | 窗口标题 |
| icon | string | 窗口图标路径 |
| resizable | boolean | 是否可调整大小 |
| movable | boolean | 是否可移动 |
| minimizable | boolean | 是否可最小化 |
| maximizable | boolean | 是否可最大化 |
| fullscreen | boolean | 是否全屏 |
| webPreferences | object | WebPreferences 配置 |
窗口操作方法
// 加载URL或文件
mainWindow.loadFile('index.html');
mainWindow.loadURL('https://example.com');
// 窗口状态控制
mainWindow.show();
// 隐藏,非最小化
mainWindow.hide();
mainWindow.focus();
// 最小化
mainWindow.minimize();
mainWindow.maximize();
// 将窗口从最小化状态恢复到以前的状态
mainWindow.restore();
mainWindow.close();
// 获取窗口尺寸和位置
const size = mainWindow.getSize();
const position = mainWindow.getPosition();
// 设置窗口尺寸和位置
mainWindow.setSize(1000, 800);
mainWindow.setPosition(100, 100);
Menu菜单
工具栏菜单
总常用的应该是取消工具栏
win.setMenu(null);
修改原生菜单
// 创建菜单
const menu = Menu.buildFromTemplate(menuTemplate);
// 设置应用菜单
Menu.setApplicationMenu(menu);
上下文菜单
在主进程中全局配置
// background.js
// 创建右键菜单
const contextMenu = Menu.buildFromTemplate([
{ label: "刷新", role: "reload" },
{ label: "复制", role: "copy" },
{ label: "粘贴", role: "paste" },
])
// 当页面触发 contextmenu 事件时,弹出菜单
mainWindow.webContents.on("context-menu", () => {
contextMenu.popup({ window: mainWindow })
})
(细粒度/组件级):preload.js + IPC + 渲染进程侧调用
// src/App.vue
<template>
<div id="app" @contextmenu.prevent="showContextMenu">
<router-view/>
<input type="text" placeholder="Right-click me too!" />
</div>
</template>
showContextMenu(event) {
// 判断点击的是否為可编辑區域 (如 input, textarea)
const isEditable = event.target.tagName === 'INPUT' || event.target.tagName === 'TEXTAREA';
window.electronAPI.showContextMenu(isEditable);
}
// src/preload.js
const { contextBridge, ipcRenderer } = require('electron')
contextBridge.exposeInMainWorld('electronAPI', {
showContextMenu: (isEditable) => {
ipcRenderer.send('show-context-menu', isEditable)
}
})
// background.js
ipcMain.on('show-context-menu', (event, isEditable) => {
// 根據 isEditable 參數動態建立選單範本
const template = isEditable ? [] : [];
const menu = Menu.buildFromTemplate(template)
menu.popup({ window: BrowserWindow.fromWebContents(event.sender) })
})
// ... 其他程式碼
对话框dialog
文件对话框
const { dialog } = require('electron');
// 打开文件对话框
dialog.showOpenDialog(mainWindow, {
properties: ['openFile', 'multiSelections'],
filters: [
{ name: '文本文件', extensions: ['txt'] },
{ name: '所有文件', extensions: ['*'] }
]
}).then(result => {
if (!result.canceled) {
const filePaths = result.filePaths;
// 处理选中的文件
}
});
filters项是文件类型的下拉项,上面代码就是有两个下拉项
消息对话框
const { dialog } = require('electron');
// 消息对话框
dialog.showMessageBox(mainWindow, {
type: 'info',
title: '提示',
message: '这是一个提示消息',
buttons: ['确定', '取消'],
}).then(result => {
if (result.response === 0) {
// 用户点击了确定
} else {
// 用户点击了取消
}
});
系统通知Notification
const { Notification } = require('electron');
// 创建通知
const notification = new Notification({
title: '通知',
body: '这是一个系统通知',
icon: 'path/to/icon.png'
});
// 显示通知
notification.show();
// 处理通知点击事件
notification.on('click', () => {
// 处理点击事件
});
// 处理通知关闭事件
notification.on('close', () => {
// 处理关闭事件
});
注意:这个通知是在操作系统的右下角或右上角通知,不是Electron应用内的弹窗!!!
进程间通信(IPC)
概念:
IPC:进程间通信 (IPC) 是在 Electron 中构建功能丰富的桌面应用程序的关键部分之一。 由于主进程和渲染器进程在 Electron 的进程模型具有不同的职责,因此 IPC 是执行许多常见任务的唯一方法,例如从 UI 调用原生 API 或从原生菜单触发 Web 内容的更改。
IPC通信的模式
简单口诀send与on,invoke与handle,webContents与on
渲染器进程到主进程(单向)
vue页面调用
window.electronAPI.setTitle()
preload.js预加载脚本中定义context bridge上下文通信桥
const { contextBridge, ipcRenderer } = require('electron')
contextBridge.exposeInMainWorld('electronAPI', {
setTitle: (title) => ipcRenderer.send('set-title', title)
})
background.js中通过on语法监听
ipcMain.on('set-title', handleSetTitle)
渲染器进程到主进程(双向)
const { contextBridge, ipcRenderer } = require('electron')
contextBridge.exposeInMainWorld('electronAPI', {
openFile: () => ipcRenderer.invoke('dialog:openFile')
})
const filePath = await window.electronAPI.openFile()
主进程到渲染器进程
mainWindow.webContents.send('update-counter', -1)
const { contextBridge, ipcRenderer } = require('electron')
contextBridge.exposeInMainWorld('electronAPI', {
onUpdateCounter: (callback) => ipcRenderer.on('update-counter', (_event, value) => callback(value))
})
加载预加载脚本后,渲染器进程应有权访问 window.electronAPI.onUpdateCounter() 监听器函数
渲染进程直接调用Electron的API
如果在创建BrowserWindow时,配置了一下四项
nodeIntegration: true,//node环境继承开启
contextIsolation: false,//上下文隔离关闭
webSecurity: false,// 同源策略关闭
enableRemoteModule: true,//
那么,渲染器进程可以直接访问Electron的API,无需IPC通信,但这样做存在安全性隐患,故一般直接调用
Tips:渲染进程调用时使用window.require('electron').remote.dialog.showMessageBox,否则可能出现编译错误
clipboard类
clipboard.readText([type])
type string (optional) -可以是 selection 或 clipboard; 默认为 'clipboard'. selection 仅在 Linux 中可用。
渲染进程使用 Clipboard API和主进程使用clipboard.readText()的区别
clipboard的优势:
- 不需要用户交互
- 直接能读取,不受
https或权限限制。
- 直接能读取,不受
- 协议无关
- 无论渲染进程是
file://、http://、https://都可以工作。
- 无论渲染进程是
- 可读写更多格式
- 除了
text,还能操作image、html、rtf等
- 除了
| 场景 | 推荐方案 |
|---|---|
| 你只需要在前端 Vue 页面里临时读取文本,且不想依赖 Electron 模块 | 用 navigator.clipboard.readText() |
| 你需要稳定、不依赖安全上下文、无需用户交互,甚至需要读取图片/HTML 等格式 | 用 electron.clipboard.readText()(主进程或 preload) |
| 需要在渲染进程直接访问系统剪切板 | 在 preload 里通过 contextBridge 暴露 clipboard API 给渲染进程 |