系列文章目录
系列第一篇: vue3+electron开发桌面软件入门与实战(0)——创建electron应用
文章目录
- 系列文章目录
- 前言
- 一、我们如何思考
- 二、解决问题
- 1.选择方案
- 2. 发现electron多开窗口监听
- 3.查找可使用的官方参数
- 4.示例代码
- 总结
前言
从本系列第六篇文章开始,我们一共用三篇文章讲解了系统级右键实现文件上传、手动修改注册表实现级联菜单、electron操作修改注册表实现级联菜单。
网络上大部分文章也止步于此,但是在很多业务场景下,我们都需要右键选中多个文件,实现一键上传功能。如图:
网上部分文章也提到了多选文件(图片)并上传,但是基本都未进行任何代码操作,而是使用鼠标拖动多个文件放到electron应用的图标,利用electron默认的能力实现多文件上传,针对我们具体的需求,这种方式只能算是一种无法解决问题时的妥协方案。
一、我们如何思考
遇到问题我们应该如何思考呢?
通过查阅网络资料,我们可以大胆设想,可能有以下两种方案:
- 我们依赖注册表参数“1%”获取文件路径,发现这个参数只能传递一个文件路径。那么有没有一个类似的参数,或者通过某种参数操作,可以获取多个文件路径?
- 通过查阅资料,发现有大佬通过cmd命令行传参时,可以控制黑窗口的显示,当出现第二个窗口时,不显示,并把获得的参数传递给第一个窗口,我们能不能借鉴这种方式,把多个文件路径都汇集到第一个应用窗口?
二、解决问题
1.选择方案
老规矩,如果着急借鉴代码实现效果,可以不用看我bb解决问题的方式。直接跳转到最后。
最初我是倾向于借助注册表参数解决问题的,所以研究了很多注册表相关知识,发现以我目前水平,这条路走不通。
所以最终确定为选择第二种方案,后续文件打开的应用窗口将参数传递给第一个窗口。
2. 发现electron多开窗口监听
借鉴网上大佬cmd多窗口时传参的思路,我们如果想要实现electron多窗口传参,就需要在electron打开新窗口的时候,拿到参数,传递给第一个打开的活跃窗口。
这个方案是很麻烦的,全局参数、进程通信(不是electron的进程概念,而是windows进程)、参数管理……想想都头大,所以我开了个头,就放弃继续深入了。因为这时候,我发现这个场景似曾相识。
没错,就是我最开始写这个项目的时候,为了防止多开窗口,在electron的main.js写过一个监听:
app.on('second-instance', (event, commandLine, workingDirectory, additionalData) => {
// 有人试图运行第二个实例,我们应该关注我们的窗口
if (win) {
if (win.isMinimized()) win.restore()
win.focus()
}
})
这个监听就是在做windows层面的进程管理(如果不理解,可以略过这句话,直接看后面的大白话。)
说白了,这个监听就是当我们打开第二个窗口的时候,electron可以监听到,然后我们在里面做了个判断,如果win窗口存在,那么就不要打开窗口了,而是显示我们存在的窗口。
这不就是electron官方提供的多开窗口监听吗,用官方的,省事不说,起码不会有太多bug吧。
如果我们去掉这段监听代码,就会发现如果多选文件后打开应用,那么我们选择了几个文件,就会打开几个应用,并且每个应用都能打印出对应文件的地址。即应用拿到了各自文件的地址。
所以我们现在要做的,就是怎么把后续打开应用中的文件地址,都传递给第一个应用窗口。
3.查找可使用的官方参数
我们为什么要使用大企业背书的框架?就是因为我们相信他们是在做产品,而不是仅仅做个项目。产品,就要考虑更多场景,所以我觉得官方既然想到了多窗口管理,就不会不考虑多窗口参数间的通讯。
果然,经过查阅得知additionalData传递的就是后续打开窗口的参数。代码如下:
app.on('second-instance', (event, commandLine, workingDirectory, additionalData) => {
// 输出从第二个实例中接收到的数据,传入到fileController中
const url=argvController.getConfigByArgv('getUrl',additionalData.argv)
fileController.addFileUrl(url)
// 有人试图运行第二个实例,我们应该关注我们的窗口
if (win) {
if (win.isMinimized()) win.restore()
win.focus()
}
})
不用关心getConfigByArgv方法和fileController.addFileUrl,这只是我封装的方法,如何去操作拿到的文件地址。
这一部分真正核心的代码就是一个参数:additionalData.argv。这里面放着后面窗口的argv参数。而通过本系列前面单文件上传的文章可以知道,argv中保存着文件的地址。
我们拿到所有文件地址后,就可以随意操作多选的文件了。
4.示例代码
- main.js中监听多文件打开的窗口参数
app.on('second-instance', (event, commandLine, workingDirectory, additionalData) => {
// 输出从第二个实例中接收到的数据,传入到fileController中
const url=argvController.getConfigByArgv('getUrl',additionalData.argv)
fileController.addFileUrl(url)
// 有人试图运行第二个实例,我们应该关注我们的窗口
if (win) {
if (win.isMinimized()) win.restore()
win.focus()
}
})
- getConfigByArgv是我用来解析argv参数的方法,这里为了拓展性写了个策略模式,如果不好接受,不用有心智负担,只需要按照自己喜欢的方式,从argv中拿到文件地址就可。
const argvTypes={
//为获取参数设计策略模式
getUrl(argv){
//获取地址
for (let i = 0; i < argv.length; i++) {
if (argv[i].includes('upload-tome') ) {
return argv[i + 1]
break
}else if(argv[i].includes('upload-toother')){
return argv[i + 1]
break
}else if(argv[i].includes('upload-backgorundget')){
return argv[i + 1]
break
}
}
},
getTomeType(argv){
//获取tome后面附带的参数值
for (let i = 0; i < argv.length; i++) {
if (argv[i].includes('upload-tome') ) {
return argv[i]
break
}
}
},
getCmdType(argv){
//获取tome、toother两个参数
let flag='get'
// console.log(config)
for (let i = 0; i < argv.length; i++) {
// debugger
if (argv[i].includes('upload-tome') ) {
flag=config.toTypeList.tome
break
}else if(argv[i].includes('upload-toother')){
flag=config.toTypeList.toother
// flag='tome'
}else if(argv[i].includes('upload-get')){
flag=config.toTypeList.get
}else if(argv[i].includes('upload-backgorundget')){
flag=config.toTypeList.get
}
}
return flag
}
}
const getConfigByArgv=(type,argv)=>{
return argvTypes[type](argv)
}
- addFileUrl方法就比较简单了,就是为了得到一个文件数组:
let fileUrlArr = []
//省略无关代码...
const addFileUrl = (v) => {
fileUrlArr.push(v)
}
- 组合最终的files:
const progressArgv = progress.argv
const cwd = progress.cwd()
let url = argvController.getConfigByArgv('getUrl',progressArgv) //获取第一实例的文件地址
let files = []
files.push(url, ...fileUrlArr)
大家对上面的代码应该不陌生,是系列前面文章里获取文件地址的一段代码,现在我们得到了第二个窗口后的文件数组fileUrlArr,只需要和第一个窗口的文件地址合并为新的数组files,就可得到最终结果。
结合文章开头的图,点击上传后,在文件列表显示已上传的文件详情:
总结
至此,关于文件上传的基本功能都已完成,后续可能还会有一些样式的优化,比如正常打开时,应用在屏幕中央,通过文件右键打开时,应用在右下角有一些特殊样式。
用最简单的方式,完成产品的需求,才是一个技术人该有的追求。千万不要成为企业里那个一整天都在反复修改代码、反复解决问题的人。短期看,项目离不开你,长期看,你只能干到35。
能看到这的应该都是对electron比较感兴趣的同学,我最近在参加csdn新星计划导师活动,我对活动细节不了解也不太关心,不过有兴趣的同学可以免费报名,有集中讨论讲解的环节,应该比私信要效率更高。
活动地址请戳:https://bbs.csdn.net/topics/615149275