喔喔屋

断剑重铸之日


  • 首页

  • 标签

  • 分类

  • 归档

踩坑 electron-vue

发表于 2020-01-05
字数统计: 1.7k | 阅读时长 ≈ 8

electron-vue 用于构建桌面版应用程序

第一次开发桌面应用。在此记录使用electron-vue搭建桌面版应用所遇到的问题。

process is not defined

按照官网步骤搭建项目,运行npm run dev 时出现 process is not defined 错误。
解决方案:
在.electron-vue/webpack.renderer.config.js和.electron-vue/webpack.web.config.js文件中找到HtmlWebpackPlugin代码段并更改为如下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
new HtmlWebpackPlugin({
filename: 'index.html',
template: path.resolve(__dirname, '../src/index.ejs'),
templateParameters(compilation, assets, options) {
return {
compilation: compilation,
webpack: compilation.getStats().toJson(),
webpackConfig: compilation.options,
htmlWebpackPlugin: {
files: assets,
options: options
},
process,
};
},
minify: {
collapseWhitespace: true,
removeAttributeQuotes: true,
removeComments: true
},
nodeModules: process.env.NODE_ENV !== 'production'
? path.resolve(__dirname, '../node_modules')
: false
}),

打包找不到文件报错

第一次运npm run build时报了一大堆文件下载错误,比如electron-vxxx-winxxx.zip 、nsis-xxx等
解决方案:
自己去taobao镜像网站或github上下载相关版本的文件包,放入本地相关目录下。

自定义桌面窗口栏目

通过配置主进程src\main\index.js文件相关属性,完成窗口自定义

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import { app, BrowserWindow, ipcMain} from 'electron'
mainWindow = new BrowserWindow({
height: 880,
useContentSize: true,
width: 1200,
minWidth: xxx,
minHeight: xxx,
title: "XXX",
frame: false, //添加后自定义标题//自定义边框
resizable: false, //可否缩放
movable: true, //可否移动
})
// 相关事件
ipcMain.on('close', e => {
mainWindow.close()
})
ipcMain.on('minimize', e => {
mainWindow.minimize()
})
ipcMain.on('unmaximize', e => {
mainWindow.unmaximize()
})
ipcMain.on('maximize', e => {
mainWindow.maximize()
})

vue页面监听事件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
const { ipcRenderer } = require("electron");
methods:{
minimize() {
ipcRenderer.send("minimize");
},
// 文档说可以用这个方法mainWindow.isMaximized()判断窗口是否最大化,但是我测试没有效果,所以就自己定义了一个状态
maximize() {
if (this.isMaxSize) {
ipcRenderer.send("unmaximize");
} else {
ipcRenderer.send("maximize");
}
this.isMaxSize = !this.isMaxSize;
},
close() {
ipcRenderer.send("close");
}
}

打包相关配置

1、图标命名自定义
修改package.json文件,在build中配置自定义图标路径和安装名称,需要在build文件夹中放置自定义图标

1
2
3
4
5
6
"build": {
"win": {
"icon": "build/icons/icon.ico",
"artifactName": "${productName}_Setup_${version}.${ext}"
}
},

2、打包后应用安装目录自定义
修改package.json文件,在build中添加配置

1
2
3
4
5
"nsis": {
"oneClick": false,
"allowToChangeInstallationDirectory": true,
"perMachine": true
},

3、自动检测版本并更新
修改package.json文件,在build中添加配置

1
2
3
4
"publish": [{
"provider": "generic",
"url": "http://xxxxxxx/download/" // 打包生成的exe安装包和latest.yml存放路径,浏览器输入地址能下载这两个文件
}]

安装 electron-updater,在 src\main\index.js中添加更新事件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
 
import {
autoUpdater
} from 'electron-updater'
// 和package.json中配置的下载地址一致
let feedUrl = "http://xxxxxxx/download/";
//检测版本更新
updateHandle(mainWindow, feedUrl);

function updateHandle(window, feedUrl) {
mainWindow = window;
let message = {
error: '检查更新出错',
checking: '正在检查更新……',
updateAva: '检测到新版本,正在下载……',
updateNotAva: '现在使用的就是最新版本,不用更新',
};
//设置更新包的地址
autoUpdater.setFeedURL(feedUrl);
//监听升级失败事件
autoUpdater.on('error', function (error) {
sendUpdateMessage({
cmd: 'error',
message: error
})
});
//监听开始检测更新事件
autoUpdater.on('checking-for-update', function (message) {
sendUpdateMessage({
cmd: 'checking-for-update',
message: message
})
});
//监听发现可用更新事件
autoUpdater.on('update-available', function (message) {
sendUpdateMessage({
cmd: 'update-available',
message: message
})
});
//监听没有可用更新事件
autoUpdater.on('update-not-available', function (message) {
sendUpdateMessage({
cmd: 'update-not-available',
message: message
})
});

// 更新下载进度事件
autoUpdater.on('download-progress', function (progressObj) {
sendUpdateMessage({
cmd: 'download-progress',
message: progressObj
})
});
//监听下载完成事件
autoUpdater.on('update-downloaded', function (event, releaseNotes, releaseName, releaseDate, updateUrl) {
sendUpdateMessage({
cmd: 'update-downloaded',
message: {
releaseNotes,
releaseName,
releaseDate,
updateUrl
}
})
//退出并安装更新包
autoUpdater.quitAndInstall();
});

//接收渲染进程消息,开始检查更新
ipcMain.on("checkForUpdate", (e, arg) => {
//执行自动更新检查
// sendUpdateMessage({cmd:'checkForUpdate',message:arg})
autoUpdater.checkForUpdates();
})
}
//给渲染进程发送消息
function sendUpdateMessage(text) {
mainWindow.webContents.send('message', text)
}

在App.vue中添加检测更新事件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<script>
const ipcRenderer = require("electron").ipcRenderer;
//接收主进程版本更新消息
ipcRenderer.on("message", (event, arg) => {
// for (var i = 0; i < arg.length; i++) {
if ("update-available" == arg.cmd) {
} else if ("download-progress" == arg.cmd) {
//更新升级进度
alert("更新中");
console.log(arg.message.percent);
} else if ("error" == arg.cmd) {
alert("更新失败");
}
}
});
//20秒后开始检测新版本
let timeOut = window.setTimeout(() => {
console.log("检查更新");
ipcRenderer.send("checkForUpdate");
}, 2000);
clearTimeout;
//间隔1小时检测一次
let interval = window.setInterval(() => {
ipcRenderer.send("checkForUpdate");
}, 3600000);
</srript>

#####首先将打包成功后生成的exe安装文件和latest.yml放到配置的下载服务器上,再修改package.json中的版本号,重新打包新的版本,把生成的安装文件和latest.yml放到下载服务器同一个位置,latest.yml会覆盖上一次生成的。应用会通过检测这个文件判断是否有新版本

1
"version": "0.0.2", // 打包版本号

#####注意:用vue-electron脚手架搭建的应用electron版本是2.xx的,我查资料说版本太低不支持自动检测更新,所以我最开始就把electron升级了,没有测试2版本是否可以自动检测更新;自动更新成功后发现每次更新都需要重新安装一次,很不友好。如果有人了解局部更新的知识,我想请教学习,谢谢。

打包安装引入外部exe或者dll文件

由于项目中需要启动另外的exe程序,所以必须把其他exe程序和electron关联起来安装
修改package.json文件,配置需要引入的相关exe程序。

1
2
3
4
"extraResources": {
"from": "./extraResources/",
"to": "./extraResources/"
}

在src\main\index.js中使用chile_process

1
2
3
4
5
6
7
8
const {
spawn
} = require('child_process')
const vmPath = require('path').join(process.cwd(),'/resources/extraResources/xxx.exe').replace(/\\/g, '\\\\')
ipcMain.on('connect-server', (e, appUrl) => {
//spawn("D:/xxx/xxx/=xxx.exe") 开发模式写绝对路径
spawn(vmPath) // 打包安装后的路径
})

#####路径方面的问题,借用https://segmentfault.com/a/1190000018878931 原作者的话
使用 nodeJS 的被执行 js 文件的绝对路径:__dirname。
返回: D:\【文件夹】\win-ia32-unpacked\resources\app.asar\dist\electron
使用 electron 文档中提到的:“当前应用程序所在目录”:app.getAppPath()。
返回: D:\【文件夹】\win-ia32-unpacked\resources\app.asar
使用 process.execPath 即可获取: D:\【文件夹】\build\win-ia32-unpacked\vsqx.exe
使用 process.cwd() 即可获取: D:\【文件夹】\build\win-ia32-unpacked
最终我选用process.cwd()方法,完成在安装程序中启动内部exe程序

基础知识

发表于 2019-10-27 | 分类于 知识点
字数统计: 2.9k | 阅读时长 ≈ 10

作用域和闭包

  1. 变量的赋值操作会执行两个动作,首先编译器会在当前作用域中声明一个变量(如果之前没有声明过),然后在运行时引擎会在作用域中查找该变量,如果能够找到就会对它赋值。
  2. 作用域是一套规则,用于确定在何处以及如何查找变量(标识符)。如果查找的目的是对变量进行赋值,那么就会使用LHS查询;如果目的是获取变量的值,就会使用RHS查询。
  3. 赋值操作符会导致LHS查询。=操作符或调用函数时传入参数的操作都会导致关联作用域的赋值操作。
  4. JavaScript 引擎首先会在代码执行前对其进行编译,在这个过程中,像 var = 2 这样的声明会被分解成两个独立的步骤:首先,var 2 在其作用域中声明新变量。这会在最开始的阶段,也就是代码执行前进行。接下来,a = 2 会查询(LHS查询)变量 a 并对其进行赋值。
阅读全文 »

Java链表实现队列

发表于 2019-09-01 | 分类于 数据结构
字数统计: 242 | 阅读时长 ≈ 1

带有尾指针的链表 O(1)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
public class LinkedListQueue<E> implements Queue<E> {
private class Node {
public E e;
public Node next;

public Node(E e, Node next) {
this.e = e;
this.next = next;
}

public Node(E e) {
this(e, null);
}

public Node() {
this(null, null);
}

@Override
public String toString() {
return e.toString();
}
}

private Node head, tail;
private int size;

public LinkedListQueue() {
head = null;
tail = null;
size = 0;
}

@Override
public int getSize() {
return size;
}

@Override
public boolean isEmpty() {
return size == 0;
}

@Override
public void enqueue(E e) {
if (tail == null) {
tail = new Node(e);
head = tail;
} else {
tail.next = new Node(e);
tail = tail.next;
}
size++;
}

@Override
public E dequeue() {
if (isEmpty()) {
throw new IllegalArgumentException("Cannot dequeue from an empty queue");
}
Node retNode = head;
head = head.next;
retNode.next = null;
if (head == null) {
tail = null;
}
size--;
return retNode.e;
}

@Override
public E getFront() {
if (isEmpty()) {
throw new IllegalArgumentException("Queue is empty");
}
return head.e;
}

@Override
public String toString() {
StringBuilder res = new StringBuilder();
res.append("Queue: front");
Node cur = head;
while (cur != null) {
res.append(cur + "->");
cur = cur.next;
}
res.append("null tail");
return res.toString();
}
}

Java链表实现栈

发表于 2019-09-01 | 分类于 数据结构
字数统计: 97 | 阅读时长 ≈ 1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
public class LinkedLsitStack<E> implements Stack<E> {
private LinkedList<E> list;

public LinkedLsitStack() {
list = new LinkedList<>();
}

@Override
public int getSize() {
return list.getSize();
}

@Override
public boolean isEmpty() {
return list.isEmpty();
}

@Override
public void push(E e) {
list.addFirst(e);
}

@Override
public E pop() {
return list.removeFirst();
}

@Override
public E peek() {
return list.getFirst();
}

@Override
public String toString() {
StringBuilder res = new StringBuilder();
res.append("Stack: top");
res.append(list);
return res.toString();
}
}

Java链表

发表于 2019-09-01 | 分类于 数据结构
字数统计: 742 | 阅读时长 ≈ 3

基本动态数据结构—-链表

添加操作:O(n)
addLast(e) O(n)
addFirst(e) O(1) (常用)
add(index,e) O(n/2) = O(n)

删除操作:O(n)
removeLast(e) O(n)
removeFirst(e) O(1) (常用)
remove(index) O(n/2) = O(n)

修改操作: O(n)
set(index,e) O(n)

阅读全文 »
12…7
邱仁亮

邱仁亮

我才发现梦想与现实之间差别

31 日志
10 分类
17 标签
RSS
GitHub E-Mail
Links
  • 学习资源
  • Web前端导航
© 2018 — 2020 邱仁亮 | Site words total count: 41.5k