electron基础
教程很细很详细了,操作也很简单,可参考官方开发文档
个人理解来说,electron就是一个把html打包成桌面应用的框架,其内置了一个Chromium可以加载各种网页,以及可以在index.js
和preload.js
中执行nodejs代码。
其中在preload.js
中可以主动暴露函数出来给前端代码调用,也可以通过postMessage向前端主动发送消息。=> 参考 添加preload.js 和 preload主动发送数据到前端
如果想给index.js
中的内容发送到前端,那就需要先发到preload.js
,再由preload.js
发送给前端。 => 参考 注册全局快捷键
创建项目时可通过Electron Forge快速创建
npm init electron-app@latest my-app
cd my-app
npm install --save-dev electron
创建好的目录结构如下,可以说是应有尽有
直接运行 npm run start
即可。
electron+vue3
项目搭建
先参考《vue项目搭建小结》搭建好vue的项目,能正常启动没问题后,执行如下命令添加electron
,文档地址为 Vue CLI Plugin Electron Builder
vue add electron-builder
选择版本为最新的即可,安装好后执行如下命令即可启动!
# 启动
npm run electron:serve
# 打包
npm run electron:build
其中 background.js
为electron的配置文件(index.js
)。
下面记录一些我用得比较多的
添加preload.js
在vue.config.js
中添加如下内容
module.exports = {
pluginOptions: {
electronBuilder: {
preload: 'src/preload.js',
}
}
}
然后在src/background.js
中添加如下内容
const path = require('path')
preload: path.join(__dirname, 'preload.js')
最后在src
目录下新建一个preload.js
即可
编写代码测试一下:
const { contextBridge } = require('electron')
const {exec} = require('child_process')
contextBridge.exposeInMainWorld('versions', {
node: () => process.versions.node,
chrome: () => process.versions.chrome,
electron: () => process.versions.electron
// we can also expose variables, not just functions
})
function executeCommand(command) {
return new Promise((resolve, reject) => {
exec(command, (error, stdout, stderr) => {
if (error) {
reject(`执行错误: ${error}`);
return;
}
resolve(stdout);
});
});
}
contextBridge.exposeInMainWorld('internal', {
getWhoami: () => executeCommand('whoami'), // 执行系统命令whoami并返回结果
getTest: function() {
return "test"
}
})
preload主动发送数据到前端
上面的例子是前端通过调用preload.js
中的暴露函数实现的获取信息,那如果要主动给前端发数据呢?研究后发现通过postMessage
发送数据会比较简单!
在 preload.js
中调用postMessage发送数据
const { contextBridge } = require('electron')
contextBridge.exposeInMainWorld('internal', {
getTest: function() {
window.postMessage({type:"hello", data:"hello post message"}, '*')
return "test"
}
})
在vue接收数据的页面中监听message事件即可。
<template>
<div class="about">
<h1>This is an about page</h1>
</div>
</template>
<script>
export default {
methods: {
testEventListener(event) { // 监听到事件后执行的操作
console.log(event)
if (event.data.type === "hello") {
console.log(event.data.data)
}
}
},
mounted() { // 注册message监听
window.addEventListener('message', this.testEventListener)
},
unmounted() { // 一定要记得注销事件监听
window.removeEventListener('message', this.testEventListener)
},
}
</script>
效果如下:
隐藏菜单
方式有很多,列举下面2个,在background.js
中修改:
autoHideMenuBar: true, // 隐藏windows上面一排的菜单栏,mac上好像没用
frame: false, // 无边框
注册全局快捷键
注册全局快捷键 option + I
,任何地方按下后都会给展示页面随机设置值。(除了全局外还有当前应用的快捷键,可以根据实际情况来判定用哪一类,具体可参考键盘快捷键)
实现流程:按下快捷键 -> 发送数据到preload.js -> preload.js发送数据到前端
1、按下快捷键,生成随机数并发送数据到preload.js
globalShortcut.register('Option+I', () => {
let randomData = require('crypto').randomBytes(16).toString('hex')
console.log(randomData)
win.webContents.send('random', randomData)
})
2、preload.js代码:接受数据,发送到前端
const { ipcRenderer } = require('electron')
ipcRenderer.on('random', (_event, value) => {
window.postMessage({type: 'test', data: value}) // postMessage直接发给前端
})
3、前端展示
<template>
<div class="about">
<h1>This is an about page</h1>
<p>{{ randomString }}</p>
</div>
</template>
<script>
export default {
data() {
return {
randomString: null
}
},
methods: {
testEventListener(event) { // 监听到事件后执行的操作
console.log(event)
if (event.data.type === "test") {
this.randomString = event.data.data
}
}
},
mounted() { // 注册message监听
window.addEventListener('message', this.testEventListener)
},
unmounted() { // 一定要记得注销事件监听
window.removeEventListener('message', this.testEventListener)
},
}
</script>
这样每次按下快捷键后,前端的内容就会同步更改
任务栏图标显示
使用Tray
const { Tray, Menu, nativeImage } = require('electron')
let tray
// 在 createWindow() 后
// const icon = nativeImage.createFromPath('src/assets/logo.png')
const icon = nativeImage.createFromDataURL('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAn1JREFUOE+lkl9IU2EYxp/vnO3sH24gyTKJErGU0uG+TcRETSRE6I+aUSR0EUUoXahgN92EQUQUXiRdRBdFGWQgSmGZOcP8E5xzZkqQYVoYs5JZm5vbONv5YpEwYfOm9/J7v+cHz/M+BP85JFHvcDiKRFF0UweN5ZUL45455ZMSItawn93Xp6El5GdnCCH7RFEc3NBtAhSX0EmDmdsT8KrpWfu1CK7G8NujYmehRl2aiXKEg6o3EdfbUbE6KYBSagcgCUaCvEotLFYewV8qvs1G8fNzDBoBUCIsV5bl+aSA+COl9InBQhrDfgZCAMb+fSWAYCJvJkbFykTbmyzEF2UH7LdztqvNei0jxXsVDEzp0Fq/jq4+A/P6uf6xCbkuJYBSWmAxMbGtPiTMLPJ49k6HrguBuBi7rDEMSUJcWyhJ0mxSCzXV9tazh0K3bvQa0VAWgcfLYZuFYeqjBlea1vFwRIf3C/wd15i7OVWIrPlwCOMftCjMjoHnGB659Hh9zYe6zjScqozglSz09PRPn04JoLlRdLcEUNZuQa1TweoawYqPQ0QhuHgkhOtPje7BYTl+rb+zKURKKctMV1FlU7C0wkFlgF4A3PMaPO/04eAlC7Q8ll1j8o6kgKM1RZOl+UpJPKzey34cv2rGifII5j0cFr7zyDAzLP7g54Zccl5SQEWpva84P3os2xrDC0lAU1UYD4b1MOgYvD6CtoYwugd0XYMj061bFYnlZMYQCBF0NIbQcc+E87VhZJhVdD42MsaQJUnSckqA0+msUFV1tGB3dG32iybt5rkg2u+aQAhTVRW1siy/3LKJG0ubzZZl0nMneQHTwSD5mtj/RMAfdNUAIGhBEhMAAAAASUVORK5CYII=')
tray = new Tray(icon)
const contextMenu = Menu.buildFromTemplate([
{
label: '点击退出',
type: 'normal' ,
click: () => { app.quit(); }
}
])
tray.setContextMenu(contextMenu) // 设置菜单
tray.setToolTip('test') // 介绍
tray.setTitle('d4m1ts') // 标题
效果如下:
打包图标生成
使用工具 electron-icon-builder
生成到 build/icons/
目录下即可,打包时就会自动带上图标。
npm install -g electron-icon-builder
electron-icon-builder --input=./public/icon.png --output=./build --flatten
打包后效果如下
注意问题
打包异常
打包时记得填写上作者author
和描述description
字段。
如果出现错误 Error: Exit code: ENOENT. spawn /usr/bin/python ENOENT
先执行 which python
找到 python2的路径,然后替换掉 /node_modules/dmg-builder/out/dmg.js
中的 "/usr/bin/python"
为查询到的真实的路径即可。
打包后首页白板
serve显示正常,build后打开首页白板,即只显示了App.vue
的内容,但是没显示其 <router-view/>
渲染的内容。
解决办法也很简单,在 App.vue
中加一个首页跳转即可。
<script>
export default {
mounted() {
this.$router.push("/")
},
}
</script>
这样再打开就一切正常了。