Electron + Vue3 开发桌面应用+附源码

什么是 Electron?

Electron 是一个使用 JavaScript、HTML 和 CSS 构建跨平台桌面应用程序的框架。它由 GitHub 开发并维护,允许开发者使用现代 Web 技术创建原生应用程序。Electron 结合了 Chromium 渲染引擎和 Node.js 运行时环境,使得开发者可以在同一个项目中同时利用前端和后端的技术栈。

Electron 主要特点

  1. 跨平台:
  • 一次编写,可在 Windows、macOS 和 Linux 上运行。
  1. Web 技术栈:
  • 使用 HTML、CSS 和 JavaScript 进行开发,降低学习成本。
  1. Node.js 集成:
  • 访问操作系统级别的功能,如文件系统操作和网络请求
  1. 丰富的生态系统:
  • 大量社区支持和第三方库,便于快速集成功能。
  1. 高性能:
  • 通过优化和底层技术支持,实现高性能应用。

基本架构

  1. 主进程:
  • 管理应用生命周期、创建和管理窗口、处理与操作系统的交互。
  • 使用 Node.js 编写,运行在 Node.js 环境中。
  1. 渲染进程:
  • 显示用户界面,每个窗口有一个独立的渲染进程。
  • 使用 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命令创建 --命令创建

  1. 导航到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
  1. 继续执行以下命令,创建 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"
},

> 打包下载慢问题解决

具体地址解决文章地址:https://blog.csdn.net/weixin_46525113/article/details/132299107?fromshare=blogdetail&sharetype=blogdetail&sharerId=132299107&sharerefer=PC&sharesource=m0_47483157&sharefrom=from_link

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 文件中常用得配置

  1. 导入必要的模块
js 复制代码
import { app, BrowserWindow, Menu, Tray, Notification, autoUpdater } from 'electron';
import path from 'path';
import { fileURLToPath } from 'url';
  1. 获取当前文件的目录路径
js 复制代码
const __dirname = path.dirname(fileURLToPath(import.meta.url));
  1. 创建主窗口
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;  // 清除窗口引用
  });
}
  1. 创建菜单栏
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);
}
  1. 创建通知
js 复制代码
// 创建通知的函数
function createNotification() {
  const notification = new Notification({
    title: '通知标题',
    body: '这是一个通知消息'
  });

  // 显示通知
  notification.show();
}
  1. 创建托盘图标
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);
}
  1. 自动更新
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();
}
  1. 应用生命周期事件
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,
  },
});
相关推荐
古木20193 分钟前
前端面试宝典
前端·面试·职场和发展
轻口味2 小时前
命名空间与模块化概述
开发语言·前端·javascript
前端小小王2 小时前
React Hooks
前端·javascript·react.js
迷途小码农零零发2 小时前
react中使用ResizeObserver来观察元素的size变化
前端·javascript·react.js
娃哈哈哈哈呀3 小时前
vue中的css深度选择器v-deep 配合!important
前端·css·vue.js
旭东怪3 小时前
EasyPoi 使用$fe:模板语法生成Word动态行
java·前端·word
ekskef_sef5 小时前
32岁前端干了8年,是继续做前端开发,还是转其它工作
前端
sunshine6415 小时前
【CSS】实现tag选中对钩样式
前端·css·css3
真滴book理喻5 小时前
Vue(四)
前端·javascript·vue.js