Electron + Vue3开发桌面应用

Electron 是一个使用 JavaScript、HTML 和 CSS 构建桌面应用程序的框架。 嵌入 Chromium 和 Node.js 到 二进制的 Electron 允许您保持一个 JavaScript 代码代码库并创建 在Windows上运行的跨平台应用 macOS和Linux——不需要本地开发经验。

node:v18.18.2     npm:v9.8.1     electron:v29.1.1

一、使用electron开发

1、初始化项目

npm init

2、安装electron

npm install electron --save-dev

之前的淘宝镜像已经过期的,这里如果报错的话重新配置electron的环境变量

在根目录下创建 .npmrc 文件,配置以下内容:

electron_mirror=https://npmmirror.com/mirrors/electron/

electron_builder_binaries_mirror=https://npmmirror.com/mirrors/electron-builder-binaries/

3、创建 index.html 文件
<!DOCTYPE html>
<html>

<head>
	<meta charset="UTF-8" />
	<!-- https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP -->
	<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self'" />
	<meta http-equiv="X-Content-Security-Policy" content="default-src 'self'; script-src 'self'" />
	<title>Hello from Electron renderer!</title>
</head>

<body>
	<h1>Hello from Electron renderer!</h1>
	<p>👋</p>
</body>

</html>
4、创建 main.js(electron主进程)文件
const { app, BrowserWindow, nativeImage, Tray, Menu } = require('electron/main')
const { join } = require('path')

const createWindow = () => {
    const win = new BrowserWindow({
        width: 800,
        height: 600
    })
    win.loadFile(join(__dirname, './index.html'))
}

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、package.json文件配置

// package.json文件

{

        "main": "./main.js",

        "script": {

                "dev": "electron ."

        }

}

终端执行 npm run dev 即可运行electron项目

具体请参考electron官网:简介 | Electron

到此为止,我们已经成功启动了electron项目。但是这样创建项目的话我们需要编写原生JS代码,可能对于某些同学来讲不太友好,没关系接下来我们可以使用 Vue3 + Electron 进行开发。

二、使用Vue3 + Electron开发项目

1、创建项目

很多同学可能会使用 npm create vue@latest 先创建 vue3 项目,再安装 electron。这样确实可以,但是需要启动两个终端分别运行 vue 和 electron 项目,还是相对比较麻烦。

这里推荐直接使用 electron-vite 框架。具体请参考:简介 | electron-vite

npm create @quick-start/electron@latest

yarn create @quick-start/electron

pnpm create @quick-start/electron

选择适合的安装命令,然后按照提示操作即可!

✔ Project name: … <electron-app>

✔ Select a framework: › vue

✔ Add TypeScript? … No / Yes

✔ Add Electron updater plugin? … No / Yes

✔ Enable Electron download mirror proxy? … No / Yes

Scaffolding project in ./<electron-app>

... Done.

2、目录结构

3、开启热更新

// package.json文件

{

        "scrpit": {

                "dev": "electron-vite dev --watch"

        }

}

 4、更换任务栏图标
// index.js主进程(省略部分代码)
import { BrowserWindow, nativeImage } from 'electron';
import { join } from 'path';
 
const createWindow = () => {
    let mainWindow = new BrowserWindow({
        icon: nativeImage.createFromPath(join(__dirname, './xxx.ico'))
    })
}
5、系统托盘图标和菜单
// index.js主进程(省略部分代码)
import { Tray, Menu, nativeImage } from 'electron';
import { join } from 'path';

let tray = new Tray(nativeImage.createFromPath(join(__dirname, './xxx.ico')));
let contextMenu = Menu.buildFromTemplate([
    {
        label: '意见反馈',
        click: () => console.log('点击了意见反馈')
    },
    {
        label: '帮助中心',
        click: () => console.log('点击了帮助中心')
    },
    {
        label: '更新检测',
        click: () => console.log('点击了更新检测')
    },
    {
        label: '退出',
        click: () => console.log('点击了退出')
    }
])

tray.setToolTip('广东彭于晏之深圳分晏'); // 鼠标悬停托盘系统图标显示
tray.setContextMenu(contextMenu);

tray.on('click', () => mainWindow.show()); // 单机托盘图标打开应用程序
6.1、打包

安装命令

npm install electron-builder --save-dev

在package.json中进行配置(这些会在创建项目时自动配置好)

// package.json文件

{

        "script": {

                "build": "electron-vite build",

                "build:win": "electron-vite && electron-builder --win", // 只打包windows

                "build:mac": "electron-vite && electron-builder --mac",

                "build:linux": "electron-vite && electron-builder --linux"

        }

}

 我的项目使用到了c++的第三方库,所以还需要其他插件

npm install electron-rebuild --save-dev

node环境无法加载c语言的第三方库,这里需要重新编译一下node_modules目录

./node_modules/.bin/electron-rebuild

(顺便提一下,node环境打印中文的话可能会出现乱码的情况,在终端输入)

chcp 65001 

 6.2、配置打包信息

// pageage.json文件(省略部分配置)
{
    "build": {
        "appId": "xxxxxxx", // 定义应用程序的唯一标识符
        "productName": "xxxxxx", // 定义应用程序的名称
        "copyright": "Copyright © 2024 ${author}", // 定义应用程序的版权信息
        "mac": {
            "icon": "./xxxxx.icns", // mac用程序的图标文件路径
            "target": [ // 定义构建目标的数组(这里定义了两种目标:dmg(磁盘映像)和 zip(压缩文件)。每种目标都指定了支持的架构)
                {
					"target": "dmg",
					"arch": [
						"x64"
					]
				},
				{
					"target": "zip",
					"arch": [
						"x64"
					]
				}
            ]
        },
        "win": {
            "icon": "./xxxxx.ico", // windows用程序的图标文件路径
            "target": [
				{
					"target": "nsis",
					"arch": [
						"x64"
					]
				}
			],
            "artifactName": "${productName}_setup_${version}.${ext}", // 定义构建产物的文件名模板
            "nsis": {
                "oneClick": false, // 取消一键安装,用户可以选择安装目录等
                "allowToChangeInstallationDirectory": true, // 是否允许用户更改安装目录
                "installerIcon": "./xxxx.ico", // 安装程序的图标
			    "uninstallerIcon": "./xxxx.ico", // 卸载程序的图标
			    "installerHeaderIcon": "./xxxx.ico", // 安装程序的头部图标
                "createDesktopShortcut": true, // 是否在桌面创建快捷方式
			    "createStartMenuShortcut": false // 是否在开始菜单创建快捷方式
            }
        }
    },
    "files": [] // 定义在构建过程中应包含的文件或文件夹
}
6.3、vue 打包多页面

在electron.vite.config.js目录下进行配置

// electron.vite.config.js文件(省略部分代码)
import { join } from 'path';
import { defineConfig } from 'electron-vite';

export default defineConfig({
    base: './', // 打包后的相对路径
    build: {
        rollupOptions: {
            input: { // 打包后目录中就会生成 index.html 和 about.html文件 
                index: join(__dirname, './src/renderer/index.html'),
                about: join(__dirname, './src/renderer/about.html')
            },
            output: {
				assetFileNames: 'assets/[name].[ext]', // 这定义了资源文件(如图片、字体等)的输出文件名格式
				chunkFileNames: 'assets/[name]-[hash].js', // 这定义了代码块(例如,由动态导入产生的代码块)的输出文件名格式
        		entryFileNames: 'assets/[name]-[hash].js' // 这定义了入口文件的输出文件名格式
			}
        }
    }
})

7、electron 应用程序更新

安装命令

npm install electron-updater --save

在 main.js 主进程中编写代码

import { app, dialog, BrowserWindow } from 'electron';
import { autoUpdater } from 'electron-updater';

let mainWindow;

const createWindow = () => {
	mainWindow = new BrowserWindow({
		width: 1080,
		height: 720,
		...
	})
}

const checkAppVersionUpdate = () => {
	// 应用退出后自动安装
	autoUpdater.autoInstallOnAppQuit = true;
	// 自动下载
	autoUpdater.autoDownload = true;
	// 检测是否有更新包并通知
	autoUpdater.checkForUpdatesAndNotify().catch();
	
	// 下载进度
	autoUpdater.on('download-progress', (prog) => {
		mainWindow.webContents.send('app-update-version', {
			speed: Math.ceil(prog.bytesPerSecond / 1000), // 网速
			percent: Math.ceil(prog.percent) // 百分比
		})
	})
	
	// 安装最新版本
	autoUpdater.on('update-downloaded', (info) => {
		let dialogOpts = {
			type: 'info',
			buttons: ['重新启动', '取消'],
			title: '应用程序更新',
			message: '已下载新版本。重新启动应用程序以安装最新版本',
			detail: info.releaseNotes
		}
		dialog.showMessageBox(dialogOpts).then(result => {
			if(result.response == 0) autoUpdater.quitAndInstall();
		})
	})
}


app.whenReady().then(() => {
	createWindow();
	setTimeout(() => checkAppVersionUpdate(), 1000);
})

详细内容请参考官网Auto Update - electron-builder

在 package.json 中配置远程更新地址

{
	"scripts": {
	
	},
	"dependencies": {
	
	},
	"devDependencies": {
	
	},
	"build": {
		"publish": [
			{
				"provider": "generic",
				"url": "http://xxx/xxx:3000/updater/" // 打包后会生成一个latest.yml文件和.exe的二进制文件, 复制到updater目录下
			}
		],
		"directories": {
			"output": "electron-dist" // 更改打包输出目录,默认是dist
		}
	}
}

 在 electron-builder.yml 中配置远程更新地址

 

全局安装serve

npm install -g serve 

启动服务

serve electron-dist 

启动后默认有个端口号3000的服务,就可以在本地开发环境进行调试

修改 package.json 中的版本号,并打包上传至服务器,程序会对比远程地址中latest.yml的版本号进行自动下载更新(复杂更新消息提示可自行参考官网进行配置,我这里就是个简单的更新安装示例,毕竟3000块有3000块的写法,都是在公司当牛马没必要那么认真对吧)

8、开发过程中踩过的坑

问题 01:可以重复打开多个程序

解决方法:

const gotTheLock = app.requestSingleInstanceLock();

const createWindow = () => {

        if(gotTheLock) {

                app.on('second-instance', () => {

                       if(mainWindow.isMinimized()) mainWindow.restore();

                       mainWindow.focus();

                })

        } else {

                app.quit();

        }

        mainWindow = new BrowserWindow({ ... });

}

问题 02:窗口调用 hide() 和 show()  事件有明显闪屏现象

解决方法:

监听窗口的ready事件,然后加上

app.whenReady().then(() => {

        ...

        app.commandLine.appendSwitch('wm-window-animations-disabled');

})

问题 03:重启程序

解决方法:

app.relaunch();

app.quit(); 

问题04:a-select下拉选择框跟随滚动条滚动

解决方法:

在组件中加入 :getPopupContainer="triggerNode => triggerNode.parentNode"

<a-select v-model:value="xxx" :options="[ ]" :getPopupContainer="triggerNode => triggerNode.parentNode"/>

 

 

问题05:vue-i18n报错 Invalid linked format

报错原因:

vue-i18n的9以上的版本中@被用作特殊字符处理,直接用会报错

解决方式:

修改前:'xxxxxxx@qq.com'

修改后:邮箱: `xxxxxxx{'@'}qq.com`

评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值