npm creat vite@latest
electron官方文档:https://www.electronjs.org/zh/docs/latest/tutorial/tutorial-first-app
npm install electron --save-dev
在package.json中增加main告诉electron的主入口文件:
添加electron的运行命令为 : npm run start
创建main.js文件,并写入以下代码(官网代码):
const { app, BrowserWindow } = require('electron')
const createWindow = () => {
const win = new BrowserWindow({
width: 800,
height: 600
})
// win.loadFile('index.html')
// 下面的url为自己启动vite项目的url。
win.loadURL('http://127.0.0.1:5173/')
// 打开electron的开发者工具
win.webContents.openDevTools({ mode: 'detach' })
}
app.whenReady().then(() => {
createWindow()
app.on('activate', () => {
if (BrowserWindow.getAllWindows().length === 0) createWindow()
})
})
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit()
}
})
运行npm run start就能成功的运行起你的第一个electron项目了。
npm run start
注意,此时你的vite项目应该也是要在运行状态下的,win.loadURL(‘http://127.0.0.1:5173/’)),其中的url就是你运行vite项目的url。相当于此时我们运行了两个项目,一个是electron项目,一个是vite的项目,然后electron相当于就是一个window/mac窗口,然后把网址塞到了这个窗口里面。后期上线就是把开发时的url地址换成已经上线的url地址就行了
此时会有一个报错:
原因:是electron安全策略的设置告警,意思是内容安全策略没有设置,或者使用了unsafe-eval的安全设置
参考解决方法:https://blog.csdn.net/hwytree/article/details/121287531
<meta http-equiv="Content-Security-Policy" content="default-src 'self' 'unsafe-inline';">
就解决了
注意:
这里你一定要深刻理解这个预加载脚本的作用,否则你会对这个预加载脚本感到很疑惑。这里解释一下这个预加载脚本的作用。
概念理解:
主进程:指的是你的electron进程
预加载脚本:electron进程与vue项目通信的直接桥梁
渲染进程:就是你的vue项目或者react项目
根据electron官网(https://www.electronjs.org/zh/docs/latest/tutorial/tutorial-preload)所说的,为了安全以及隔离环境,渲染进程与主进程之间的通信需要通过一个preload.js来进行。(总的来说这个preload.js的作用就是作为渲染进程与主进程之间的通信桥梁,做的事就是:
const { contextBridge, ipcRenderer } = require('electron')
const handleSend = async (vue_params) => {
let fallback = await ipcRenderer.invoke('sent-event', vue_params)
return fallback
}
contextBridge.exposeInMainWorld('myApi', {
handleSend: handleSend
// 能暴露的不仅仅是函数,我们还可以暴露变量
})
webPreferences: {
preload: path.join(__dirname, './preload/index.js')
}
ipcMain.handle('sent-event', (event,params) => {
console.log(params)
return '1111'
})
说明:这里主要是告诉大家怎么去引入electron的预加载脚本以及一个简单的使用。具体的通信过程大家可以参考两篇文章:
https://blog.csdn.net/weixin_44582045/article/details/128564789
https://blog.csdn.net/weixin_43239880/article/details/129563632
官网教程
此时我们已经成功的创建了一个vite+vue3+ts+electron的项目!!!
因为此时我们修改vue代码,vite会帮我们热重启。但是当我们修改electron文件的代码时,并没有脚手架帮我们热重启,所以此时我们需要添加nodemon,帮我们重启一下。
npm i nodemon -D
在package.json中的scripts添加这句进行启动electron项目,nodemon在检测到有以.js,.html结尾文件发生变动时,就会重启窗口
(如果需要改变.vue和.css的时候同时启动,也可以继续往后面加,但是没必要,因为这些文件改变,vite会自动热重启。)
"start": "nodemon --exec electron . --watch ./ --ext .js,.html"
如:添加commitLint,加入element-plus,配置别名,配置代理,添加axios及封装,添加pinia等
如何添加请查看这篇文章,每一步都有详细的步骤和用法。这里就不细说了。
基本上的桌面端项目都有托盘,所以这里也就写出来了一个简易版本的。大家可以参考一下:
// 创建系统托盘
const { Tray, Menu } = require('electron')
const path = require('path')
function createTray (app, win) {
let tray = new Tray(path.join(__dirname, '../public/favicon.ico'))
tray.setToolTip('electron_vue_demo') // 鼠标放在托盘图标上的提示信息
tray.on('click', (e) => {
if (e.shiftKey) {
app.quit()
} else {
win.show()
}
})
tray.setContextMenu(
Menu.buildFromTemplate([
{
label: '退出',
click: () => {
// 先把用户的登录状态和用户的登录信息给清楚掉,再退出
app.quit()
}
}
])
)
}
module.exports = createTray
原生的窗口不好看,很难看。且无法去修改,导致满足不了UI的效果,所以很多桌面程序都是自定义窗口。
这里主要是在main.js中创建窗口的时候加入。
const win = new BrowserWindow({
width: 800,
height: 600,
frame: false, // 不要自带的窗口
webPreferences: {
preload: path.join(__dirname, './preload/index.js')
}
})
具体其它配置,可以看这里https://www.bookstack.cn/read/electron-zh/28.md
<template>
<main>
<div class="hearder">
<span @click="toMin">最小化</span>
<span @click="toBig">最大化</span>
<span @click="toClose">关闭</span>
</div>
<div class="main">主要内容</div>
<!-- <TheWelcome /> -->
</main>
</template>
<script setup lang="ts">
import { onMounted } from 'vue'
// import TheWelcome from '../components/TheWelcome.vue'
onMounted(async () => {
let res = await window.myApi.handleSend('zm666 nb')
console.log(res)
})
const toMin = () => {
window.myApi.windowMin()
}
const toBig = () => {
window.myApi.windowMax()
}
const toClose = () => {
window.myApi.windowClose()
}
</script>
<style scoped>
.hearder {
-webkit-app-region: drag; // 添加这个 才可拖动
background-color: #ccc;
height: 40px;
width: 100%;
display: flex;
justify-content: flex-end;
align-items: center;
}
.hearder span {
margin: 0 16px;
border: 1px solid rgb(35, 34, 34);
cursor: pointer;
-webkit-app-region: no-drag;
}
.main {
height: calc(100vh - 40px);
display: flex;
align-items: center;
justify-content: center;
}
</style>
preload/index.js
const { contextBridge, ipcRenderer } = require('electron')
const handleSend = async (vue_params) => {
let fallback = await ipcRenderer.invoke('sent-event', vue_params)
return fallback
}
contextBridge.exposeInMainWorld('myApi', {
handleSend: handleSend,
// 能暴露的不仅仅是函数,我们还可以暴露变量
// 最小化
windowMin: () => {
ipcRenderer.send('window-min')
},
// 最大化
windowMax: () => {
ipcRenderer.send('window-max')
},
// 关闭窗口
windowClose: () => {
ipcRenderer.send('window-close')
}
})
这里的代码,其实就是在主进程中调用electron的事件。因为在渲染进程中无法使用electron的东西,所以需要通过预加载脚本来发送事件,主进程监听到了这个事件并作出了相应的回应。
controller/changeWindowSize.js
const { ipcMain, BrowserWindow } = require('electron')
// 最小化
ipcMain.on('window-min', event => {
const webContent = event.sender
const win = BrowserWindow.fromWebContents(webContent)
win.minimize()
})
// 最大化
ipcMain.on('window-max', event => {
const webContent = event.sender
const win = BrowserWindow.fromWebContents(webContent)
if (win.isMaximized()) {
win.restore()
} else {
win.maximize()
}
})
// 关闭
ipcMain.on('window-close', event => {
const webContent = event.sender
const win = BrowserWindow.fromWebContents(webContent)
win.close()
})
npm install electron-builder -D
配置项信息具体看官方文档:https://www.electron.build/configuration/configuration
也可以看这篇博客:https://juejin.cn/post/6844903693683261453#comment
我就直接贴我们这边的配置了(这个build和scripts同级)
"build": {
"appId": "com.zm666.desktop",//包名
"productName": "测试平台", //项目名 这也是生成的exe文件的前缀名
"asar": true,
"copyright": "Copyright © 2023 electron",//版权 信息
"publish": {
"provider": "generic",// 服务器提供商 也可以是GitHub等等
"url": ""// 服务器地址
},
"directories": { // 输出文件夹
"output": "electron-build/"
},
"extraResources": [
{
"from": "./public",
"to": "./public"
}
],
"files": [ // 打包的electron需要包含的文件,一般就是与electron的有关的打包进去
"main.js", // electron主入口文件
"controller", // 也是主入口文件,只不过拆成了两个文件
"preload" //预加载文件
],
"mac": {
"artifactName": "${productName}_${version}.${ext}",
"target": [
"dmg"
]
},
"win": {
"icon": "public/logoTemplate.ico",
"target": [
{
"target": "nsis",
"arch": [
"ia32"
]
}
],
"artifactName": "${productName}_${version}.${ext}"
},
"nsis": {
"oneClick": false,// 是否一键安装
"perMachine": false,
"allowToChangeInstallationDirectory": true,// 允许修改安装目录
"deleteAppDataOnUninstall": false,
"installerIcon": "public/favicon.ico",// 安装图标
"uninstallerIcon": "public/favicon.ico",// 创建桌面图标
"createDesktopShortcut": true,// 创建桌面图标
"createStartMenuShortcut": true,// 创建开始菜单图标
"shortcutName": "zm666测试平台" // 图标名称
},
"releaseInfo": {
"releaseNotes": "版本更新的具体内容"
}
}
在package.son中加入运行命令:
"app:dist": "electron-builder"
打包可能会失败,解决方法:
1、使用科学上网
2、参考这篇文章:https://blog.csdn.net/weixin_43239880/article/details/129532978
npm run build
将vite项目打包后的dist文件上线。将main.js中的url改成把上线后的ip地址
https://github.com/ZhangMin1998/electron_vite_ts_demo