Vue-Electron桌面应用


介绍

官方文档
教程合集

  • 可以打包成 Mac、Windows 和 Linux 三个平台的应用程序
  • 基于 Chromium 和 Node.js,可以使用 HTML, CSS 和 JavaScript 构建应用
  • 提供 Electron api 和 NodeJS api

搭建

1、 先使用 vue cli 构建项目(不作赘述)

2、 安装 vue-cli-plugin-electron-builder 插件

1
vue add electron-builder

该操作会先安装 electron,需要使用国内镜像源或开启科学上网下载,否则会报错

若科学上网或切换npm源依然无法下载,左转cnpm,请

1
2
3
4
# 安装cnpm并只想淘宝镜像源
npm install cnpm -g --registry=https://registry.npm.taobao.org
# 用cnpm安装electron
cnpm install electron

新增数据

1、package.json中新增脚本,用来运行和打包应用
运行脚本

2、新增background.js,为主进程相关操作,运行环境为 nodeJS

3、新增环境变量

用来判断是否在electron状态,即electron环境内

1
process.env.IS_ELECTRON

开发总结

进程间通讯

即窗口间通讯,使用 ipcMain 和 ipcRenderer
主进程 background.js 中:

1
2
3
4
5
import {ipcMain} from 'electron'

ipcMain.on('openImageShow', (e, ...args) => {
// 相关操作,如创建新窗口或显示新窗口等
})

渲染进程(其他页面,vue单文件等):

1
2
3
import {ipcRenderer} from 'electron'

ipcRenderer.send('openImageShow', ...args)

点击弹出窗口

只能在主线程创建窗口,新窗口需要在主线程 background.js中 new BrowserWindow(option),有两种操作方式

每次点击都创建一个新窗口(不建议)

利用上面的进程间通讯,每次点击触发时均执行 new BrowserWindow(option)

初始创建,点击仅控制显隐

new BrowserWindow(option)挂载到 createWindow 函数内,即项目启动时创建窗口,并设置 show: false

利用上面的进程间通讯,每次点击触发时均执行 BrowserWindow对象.show()即可

点左上角关闭时隐藏窗口,而非销毁

由于左上角关闭按钮点击默认是销毁进程(窗口)的,所以需要进行修改
事件close为关闭前执行,对应closed关闭后执行,在close内执行e.preventDefault()即可中止默认关闭行为,代码如下:

1
2
3
4
imageShow.on('close', (e) => {
imageShow.hide()
e.preventDefault()
})

隐藏窗口时进行操作

窗口隐藏期间,不会触发相应操作,如BrowserWindow对象.loadURL(url),会等到窗口显示时一并执行
因此如果做图片弹窗处理时,隐藏后重置loadURL,并不会执行,会留到下次打开弹窗时执行,导致出现闪烁
若必须要隐藏时重置url,可以设置定时器,如下:

1
2
3
4
5
6
7
imageShow.on('close', (e) => {
imageShow.loadURL('http://localhost:12618/view.html#/showImage?url=&imageList=')
setTimeout(() => {
imageShow.hide()
}, 1)
e.preventDefault()
})

自定义应用头部并可拖拽

自带的头部(最大小化关闭那一栏)有没有感觉很丑?来自定义吧。
首先需要在BrowserWindow配置对象中添加frame: false

1
2
3
4
5
6
7
function createWindow() {
window = new BrowserWindow({
// 无框架模式
frame: false,
...
})
}

并通过ipcMain通讯,创建最小化和关闭监听

1
2
3
4
5
6
7
8
// 初始化窗口最小化
ipcMain.on('init-window-min', function () {
initWindow.minimize()
})
// 初始化关闭
ipcMain.on('init-window-close', function () {
initWindow.close()
})

之后在渲染进程中随意编写你想要的头部结构和样式后,点击对应按钮后,触发相关监听

1
2
3
4
5
6
7
8
/* 最小化窗口 */
document.getElementById('min-window').onclick = function () {
ipcRenderer.send('init-window-min')
}
/* 关闭窗口 */
document.getElementById('close-window').onclick = function () {
ipcRenderer.send('init-window-close')
}

一顿操作后发现,怎么办,不能拖拽呀
不用急,给你想要拖拽的部分设置一下css属性,如下

1
2
3
.init-box .control-nav {
. . . -webkit-app-region: drag;
}

同时要对被包裹在其内的按钮设置no-drag,否则你会非常苦逼的发现按钮不能点击了

1
2
3
.init-box .control-nav li {
. . . -webkit-app-region: no-drag;
}

配置项目图标

使用electron-icon-builder, 生成符合Electron的图标

安装

1
npm install --save-dev electron-icon-builder

package.json 中配置生成命令

1
"electron:generate-icons": "electron-icon-builder --input=./public/icon.png --output=build --flatten"

生成图标

1
npm run electron:generate-icons

使用

1
2
3
4
5
import path from 'path'

const win = new BrowserWindow({
icon: path.join(__static, 'icon.png')
})

打包时文件复制到程序目录下

我希望app安装完毕后,项目根目录下的IEDriverServer.exe会出现在安装目录下,需在package.json中做如下配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
{
...
"build": {
"extraResources": [
{
// 该路径下没有文件时不会复制
"from": "./IEDriverServer.exe",
// 默认打包到安装目录里的resources目录下,所以使用了..指向安装根目录
"to": ".."
},
{
// 可进行多个文件的复制配置
"from": "",
"to": ""
}
]
}
...
}

问题处理

node自带属性无法使用

初次发现于引入ipc通讯时,报错__dirname is not defined,原因是electron默认不允许渲染进程使用node自带相关属性,需要对配置进行一些修改

vue.config.js中,添加 nodeIntegration: true,如下:

1
2
3
4
5
6
7
module.exports = {
pluginOptions: {
electronBuilder: {
nodeIntegration: true
}
}
}

若未使用vue,直接使用本地html文件,则需要在electron入口js文件的new BroserWindow中配置,如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// 在外部声明,方便挂载事件销毁等操作
let initWindow = null

function openInitWindow() {
initWindow = new BrowserWindow({
width: 960,
height: 700,
minWidth: 725,
minHeight: 480,
// 重点在这里,配置这两条即可
webPreferences: {
nodeIntegration: true,
// Electron12 之后被默认启用,之前的版本默认关闭,可以不设置此项
contextIsolation: false,
}
})

initWindow.webContents.openDevTools()
initWindow.loadFile(path.join(__dirname, 'index.html'))
}

修改完毕后重新运行项目即可

应用启动长时间白屏问题

应用启动时可能由于加载原因,出现长时间白屏,这时候需要使用ready-to-show事件,当应用准备完毕后再让window显示出来,代码如下

1
2
3
4
5
6
7
8
9
10
11
function createWindow() {
window = new BrowserWindow({
// 初始隐藏window不显示
show: false,
...
})
// 创建事件监听,当应用准备完毕时,显示window
initWindow.on('ready-to-show', function() {
this.show()
})
}

参考