什么是 Electron?
Electron 是一个使用 JavaScript、HTML 和 CSS 构建跨平台桌面应用程序的框架。它由 GitHub 开发并维护,允许开发者使用现代 Web 技术创建原生应用程序。Electron 结合了 Chromium 渲染引擎和 Node.js 运行时环境,使得开发者可以在同一个项目中同时利用前端和后端的技术栈。
Electron 主要特点
- 跨平台:
- 一次编写,可在 Windows、macOS 和 Linux 上运行。
- Web 技术栈:
- 使用 HTML、CSS 和 JavaScript 进行开发,降低学习成本。
- Node.js 集成:
- 访问操作系统级别的功能,如文件系统操作和网络请求
- 丰富的生态系统:
- 大量社区支持和第三方库,便于快速集成功能。
- 高性能:
- 通过优化和底层技术支持,实现高性能应用。
基本架构
- 主进程:
- 管理应用生命周期、创建和管理窗口、处理与操作系统的交互。
- 使用 Node.js 编写,运行在 Node.js 环境中。
- 渲染进程:
- 显示用户界面,每个窗口有一个独立的渲染进程。
- 使用 Chromium 渲染引擎,运行 Web 页面和应用。
- 可访问 Node.js API,但默认开启上下文隔离以提高安全性和性能。
1. 第一步创建一个electron + VUE3项目
复制下面代码输入到PowerShell , 因为我们用不到路由ts等 , 创建项目得时候一路回车点击否就好了,想要用得可自行配置
js
```# 项目名称,默认为 electron+vue3 名称自取
# 项目名称,默认为 electron+vue3
$project_name = "electron+vue3"
# 切换到淘宝镜像
npm config set registry https://registry.npm.taobao.org
# 设置 Electron 镜像
$env:ELECTRON_MIRROR="https://npmmirror.com/mirrors/electron/"
# 安装 create-vue
npm install -g create-vue
# 初始化 Vue 项目
create-vue $project_name
# 进入项目目录
Set-Location $project_name
# 安装依赖
npm install
# 安装 Electron
npm install electron --save-dev
# 启动开发服务器
npm run dev
在根目录创建 electron 文件夹,新建 index.html 文件,添加如下代码: 在 electron 目录下新建文件 main.js命令创建 --命令创建
- 导航到electron+vue3项目根目录,运行PowerSholl运行下列代码(创建 electron 文件夹建立index.thml文件并初始化html文件)
项目根目录下PowerShell输入
js
mkdir electron ; cd electron ; `
$htmlContent = @'
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Electron App</title>
</head>
<body>
<h1>Hello, Electron!</h1>
</body>
</html>
'@ ; `
Set-Content -Path index.html -Value $htmlContent -Encoding utf8
- 继续执行以下命令,创建 main.js 文件并添加内容
js
# 定义 main.js 内容并写入文件
$jsContent = @'
// 引入 Electron 的 app 和 BrowserWindow 模块
const { app, BrowserWindow } = require('electron');
// 引入 Node.js 的 path 模块,用于处理文件路径
const path = require("path");
// 创建主窗口的函数
const createWindow = () => {
// 创建一个新的浏览器窗口
const mainWindow = new BrowserWindow({
width: 800, // 设置窗口宽度为 800 像素
height: 600, // 设置窗口高度为 600 像素
});
// 使用 loadFile 方法加载 electron/index.html 文件
// path.join(__dirname, "./index.html") 用于构建文件的绝对路径
mainWindow.loadFile(path.join(__dirname, "./index.html"));
};
// 当 Electron 应用准备就绪时,调用 createWindow 函数
app.whenReady().then(() => {
createWindow();
});
// 当所有窗口关闭时,退出应用(除了 macOS)
app.on("window-all-closed", () => {
if (process.platform !== "darwin") { // 如果不是 macOS 系统
app.quit(); // 退出应用
}
});
// 当应用被激活时,创建一个新的窗口(主要用于 macOS)
app.on("activate", () => {
if (BrowserWindow.getAllWindows().length === 0) { // 如果当前没有打开的窗口
createWindow(); // 创建新的窗口
}
});
'@ ; `
Set-Content -Path main.js -Value $jsContent -Encoding utf8
3. 创建完成后文件位置示例图,可以手动创建
indin.html 完整代码
js
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Electron App</title>
</head>
<body>
<h1>Hello, Electron!</h1>
</body>
</html>
main.js 完整代码
js
// 引入 Electron 的 app 和 BrowserWindow 模块
const { app, BrowserWindow } = require('electron');
// 引入 Node.js 的 path 模块,用于处理文件路径
const path = require("path");
// 创建主窗口的函数
const createWindow = () => {
// 创建一个新的浏览器窗口
const mainWindow = new BrowserWindow({
width: 800, // 设置窗口宽度为 800 像素
height: 600, // 设置窗口高度为 600 像素
});
// 使用 loadFile 方法加载 electron/index.html 文件
// path.join(__dirname, "./index.html") 用于构建文件的绝对路径
mainWindow.loadFile(path.join(__dirname, "./index.html"));
};
// 当 Electron 应用准备就绪时,调用 createWindow 函数
app.whenReady().then(() => {
createWindow();
});
// 当所有窗口关闭时,退出应用(除了 macOS)
app.on("window-all-closed", () => {
if (process.platform !== "darwin") { // 如果不是 macOS 系统
app.quit(); // 退出应用
}
});
// 当应用被激活时,创建一个新的窗口(主要用于 macOS)
app.on("activate", () => {
if (BrowserWindow.getAllWindows().length === 0) { // 如果当前没有打开的窗口
createWindow(); // 创建新的窗口
}
});
4. 编辑 package.json 文件
项目根目录下PowerShell输入
js
# 备份 package.json 文件
Copy-Item -Path package.json -Destination package.json.bak
# 新的内容
$newContent = @'
{
"name": "my-electron-app",
"version": "1.0.0",
"main": "electron/main.js",
"scripts": {
"electron:dev": "electron ."
}
}
'@
# 写入新的内容到 package.json 文件
Set-Content -Path package.json -Value $newContent
# 查看修改后的 package.json 文件内容
Get-Content -Path package.json
添加有延迟,可自行添加
"main": "electron/main.js" 跟 "electron:dev": "electron ."
package.json完整示例:
{
"name": "electron-vue3",
"version": "0.0.0",
"private": true,
"type": "module",
"main": "electron/main.js",
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview",
"electron:dev": "electron ."
},
"dependencies": {
"vue": "^3.5.12"
},
"devDependencies": {
"@vitejs/plugin-vue": "^5.1.4",
"electron": "^33.0.2",
"vite": "^5.4.10"
}
}
5. 运行Electron
js
npm run electron:dev
运行成功示例图:
6. Electron + Vue3结合
-
编辑 package.json 文件,确定本地运行端口
-
port: 3000
export default defineConfig({
server: {
port: 3000
},
plugins: [
vue(),
],resolve: { alias: { '@': fileURLToPath(new URL('./src', import.meta.url)) } }
})
-
编辑 electron/main.js 文件,修改运行为本地
-
win.loadURL('http://localhost:3000');
js
import { app, BrowserWindow } from 'electron';
import path from 'path';
import { fileURLToPath } from 'url';
// 获取当前文件的目录路径
const __dirname = path.dirname(fileURLToPath(import.meta.url));
let win; // 使用 let 声明 win 变量
function createWindow() {
win = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
nodeIntegration: true,
contextIsolation: false,
},
});
// 生成文件路径
const indexPath = path.join(__dirname, '../dist/index.html');
console.log('Loading URL:', `file://${indexPath}`);
// 加载 Vue 开发服务器的地址
//也可以替换为你项目得域名IP
// win.loadURL('http://localhost:3000');
win.loadURL(`file://${indexPath}`);
// 监听窗口关闭事件
win.on('closed', () => {
win = null; // 清除引用
});
}
app.whenReady().then(() => {
createWindow();
app.on('activate', () => {
if (BrowserWindow.getAllWindows().length === 0) {
createWindow();
}
});
});
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit();
}
});
5. 再次Electron
js
npm run electron:dev
运行效果示例图:
4. 打包应用
- 安装 electron-builder
js
npm install electron-builder --save-dev
或者
yarn add electron-builder --dev
- 修改 Vite 配置
- 在 vite.config.js 中,将 base 选项设置为 "./",以确保打包后的资源路径正确。
js
export default defineConfig({
base: './',
plugins: [vue()],
// 其他配置项
});
- 修改 Electron 主进程配置
- 在 electron/main.js 文件中,修改 mainWindow.loadURL 的参数为 Vue 打包后的文件路径。
js
// 加载 Vue 打包后的文件路径
mainWindow.loadURL(`file://${path.join(__dirname, '../dist/index.html')}`);
- 在 package.json 中添加打包 Electron 的脚本electron:build;
js
"main": "electron/main.js",
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview",
"electron:dev": "electron .",
"electron:build": "npm run build && electron-builder"
},
> 打包下载慢问题解决
js
npm config edit
文件添加
js
registry=https://registry.npmmirror.com
electron_mirror=https://cdn.npmmirror.com/binaries/electron/
electron_builder_binaries_mirror=https://npmmirror.com/mirrors/electron-builder-binaries/
打包后文件dist目录
图片示例:
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
图片示例:双击应用打开:
7. 优化
- 将 vite 和 electron 的开发命令合并为一个脚本,以便在启动开发环境时同时运行 Vite 和 Electron。这可以通过使用 concurrently 包来实现
安装 concurrently 包
js
npm install concurrently@7 --save-dev
##好像只有指定7版本好用其他版本没试过,默认最新得报错,原因不详,不计较,7版本就行
优化 package.json 脚本
js
"electron:dev": "concurrently "vite" "electron ."",
完整package.json代码示例
js
{
"name": "electron-vue3",
"version": "0.0.0",
"private": true,
"type": "module",
"main": "electron/main.js",
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview",
"electron:dev": "concurrently "vite" "electron ."",
"electron:build": "npm run build && electron-builder"
},
"dependencies": {
"vue": "^3.5.12"
},
"devDependencies": {
"@vitejs/plugin-vue": "^5.1.4",
"concurrently": "^7.6.0",
"electron": "^33.0.2",
"electron-builder": "^25.1.8",
"vite": "^5.4.10",
"wait-on": "^6.0.1"
},
"description": "An Electron application with Vue 3 using Vite",
"author": "Your Name <your.email@example.com>",
"build": {
"appId": "com.example.electron-vue3",
"productName": "Electron-vue3桌面应用",
"directories": {
"output": "dist"
},
"files": [
"dist/**/*",
"electron/main.js"
],
"win": {
"target": "nsis",
"requestedExecutionLevel": "highestAvailable"
}
}
}
以上代码完整gitee:https://gitee.com/gaiya001/Electron-Vue3-test.git
### 到目前为止一个完整得代码初始框架就搭建好啦,你可以在上面新建自己得项目啦,如果有其他问题请在评论区留言!
Electron中 main.js 文件中常用得配置
- 导入必要的模块
js
import { app, BrowserWindow, Menu, Tray, Notification, autoUpdater } from 'electron';
import path from 'path';
import { fileURLToPath } from 'url';
- 获取当前文件的目录路径
js
const __dirname = path.dirname(fileURLToPath(import.meta.url));
- 创建主窗口
js
// 创建主窗口的函数
function createWindow() {
// 创建一个新的 BrowserWindow 实例
const win = new BrowserWindow({
width: 800, // 窗口宽度
height: 600, // 窗口高度
webPreferences: {
nodeIntegration: true, // 允许 Node.js 集成
contextIsolation: false, // 禁用上下文隔离
},
});
// 加载 Vue 应用的 HTML 文件
win.loadFile(path.join(__dirname, 'dist/index.html'));
// 监听窗口关闭事件
win.on('closed', () => {
win = null; // 清除窗口引用
});
}
- 创建菜单栏
js
// 创建菜单栏的函数
function createMenu() {
const template = [
{
label: '文件',
submenu: [
{ label: '打开', click: () => console.log('打开文件') },
{ label: '保存', click: () => console.log('保存文件') },
{ type: 'separator' },
{ role: 'quit' } // 退出应用
]
},
{
label: '编辑',
submenu: [
{ role: 'undo' }, // 撤销
{ role: 'redo' }, // 重做
{ type: 'separator' },
{ role: 'cut' }, // 剪切
{ role: 'copy' }, // 复制
{ role: 'paste' } // 粘贴
]
}
];
// 构建菜单并设置为应用菜单
const menu = Menu.buildFromTemplate(template);
Menu.setApplicationMenu(menu);
}
- 创建通知
js
// 创建通知的函数
function createNotification() {
const notification = new Notification({
title: '通知标题',
body: '这是一个通知消息'
});
// 显示通知
notification.show();
}
- 创建托盘图标
js
// 创建托盘图标的函数
function createTray() {
const tray = new Tray(path.join(__dirname, 'icon.png')); // 托盘图标路径
const contextMenu = Menu.buildFromTemplate([
{ label: '显示', click: () => win.show() }, // 显示窗口
{ label: '隐藏', click: () => win.hide() }, // 隐藏窗口
{ type: 'separator' },
{ label: '退出', click: () => app.quit() } // 退出应用
]);
// 设置托盘图标的提示文本和右键菜单
tray.setToolTip('这是托盘图标');
tray.setContextMenu(contextMenu);
}
- 自动更新
js
// 自动更新的配置
function setupAutoUpdater() {
const feedURL = 'https://example.com/update'; // 更新服务器地址
autoUpdater.setFeedURL(feedURL);
autoUpdater.on('checking-for-update', () => {
console.log('正在检查更新...');
});
autoUpdater.on('update-available', () => {
console.log('发现新版本,开始下载...');
});
autoUpdater.on('update-not-available', () => {
console.log('当前已是最新版本');
});
autoUpdater.on('update-downloaded', () => {
console.log('更新已下载,准备安装...');
autoUpdater.quitAndInstall();
});
// 检查更新
autoUpdater.checkForUpdates();
}
- 应用生命周期事件
js
// 当 Electron 完成初始化并准备好创建浏览器窗口时
app.whenReady().then(() => {
createWindow(); // 创建主窗口
createMenu(); // 创建菜单栏
createNotification(); // 创建通知
createTray(); // 创建托盘图标
setupAutoUpdater(); // 配置自动更新
app.on('activate', () => {
if (BrowserWindow.getAllWindows().length === 0) {
createWindow(); // 如果没有打开的窗口,则重新创建
}
});
});
// 当所有窗口都被关闭时
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit(); // 在 macOS 以外的平台上退出应用
}
});
主菜单 BrowserWindow 实例,窗口样式
js
win = new BrowserWindow({
// 窗口的初始宽度(以像素为单位)
width: 800,
// 窗口的初始高度(以像素为单位)
height: 600,
// 窗口左上角的 x 坐标(可选)
x: 100,
// 窗口左上角的 y 坐标(可选)
y: 100,
// 窗口的最小宽度(可选)
minWidth: 400,
// 窗口的最小高度(可选)
minHeight: 300,
// 窗口的最大宽度(可选)
maxWidth: 1200,
// 窗口的最大高度(可选)
maxHeight: 900,
// 窗口是否可以调整大小(默认 `true`)
resizable: true,
// 窗口是否可以移动(默认 `true`)
movable: true,
// 窗口是否可以最小化(默认 `true`)
minimizable: true,
// 窗口是否可以最大化(默认 `true`)
maximizable: true,
// 窗口是否可以关闭(默认 `true`)
closable: true,
// 窗口是否可以聚焦(默认 `true`)
focusable: true,
// 窗口是否总是位于最顶层(默认 `false`)
alwaysOnTop: false,
// 窗口是否全屏显示(默认 `false`)
fullscreen: false,
// 窗口是否显示在任务栏中(默认 `false`)
skipTaskbar: false,
// 窗口是否进入 kiosk 模式(默认 `false`)
kiosk: false,
// 窗口的标题
title: 'My Electron App',
// 窗口的图标路径
icon: path.join(__dirname, 'icon.png'),
// 是否显示窗口框架(默认 `true`)
frame: true,
// 窗口是否透明(默认 `false`)
transparent: false,
// 窗口的背景颜色(默认 `#FFF`)
backgroundColor: '#FFF',
// 窗口是否有阴影(默认 `true`)
hasShadow: true,
// 是否使用内容区域大小作为窗口大小(默认 `false`)
useContentSize: false,
// 窗口创建后是否立即显示(默认 `true`)
show: true,
// 窗口是否居中显示(默认 `false`)
center: true,
// 菜单栏是否自动隐藏(默认 `false`)
autoHideMenuBar: false,
// 窗口是否可以全屏(默认 `true`)
fullscreenable: true,
// 是否使用简单的全屏模式(默认 `false`)
simpleFullscreen: false,
// 渲染进程的配置
webPreferences: {
// 是否启用 Node.js 集成(默认 `false`)。启用后,可以在渲染进程中直接使用 Node.js API。
nodeIntegration: true,
// 是否启用上下文隔离(默认 `true`)。启用后,Node.js 和 Chromium 的上下文被隔离,提高安全性。
contextIsolation: false,
// 是否启用 `remote` 模块(默认 `false`)。启用后,可以在渲染进程中使用 `remote` 模块。
enableRemoteModule: false,
// 预加载脚本的路径。预加载脚本在页面加载之前执行,可以用来注入全局变量或初始化一些设置。
preload: path.join(__dirname, 'preload.js'),
// 是否启用沙箱模式(默认 `false`)。启用后,渲染进程会被限制在沙箱环境中,提高安全性。
sandbox: false,
// 是否启用 Web 安全性(默认 `true`)。禁用后,可以跨域加载资源。
webSecurity: true,
// 是否允许加载不安全的内容(默认 `false`)
allowRunningInsecureContent: false,
// 是否启用 JavaScript(默认 `true`)
javascript: true,
// 是否启用插件(默认 `false`)
plugins: false,
// 是否启用实验性功能(默认 `false`)
experimentalFeatures: false,
// 是否启用离屏渲染(默认 `false`)
offscreen: false,
},
});