wsqy182 / myhelper Goto Github PK
View Code? Open in Web Editor NEWfuckyou
fuckyou
这个问题出现的场景是,我在调用菜单的删除功能,菜单首先会删除一条数据,然后再从数据库中读取最新的数据,然后ipcMain同步消息给渲染层说删除成功.渲染层在读取最新的数据进行视图的更新。
但是我发现,视图的自动刷新有时成功,有时失败。
首先分析这个问题,删除数据,这个功能既然成功一次,说明后面每次调用都是成功的,问题就在于,数据的读取是异步的,也就是说在命令还没有删除成功的时候,代码不阻塞,继续往下执行,又从数据库中读取出了脏数据,然后刷新视图。
后面我查了下sqlite3这个模块的说明,说是这个模块最大的特点就是异步执行。
要想避免脏数据的产生,只能传递回调函数。
参考文档:https://blog.csdn.net/chuanqi305/article/details/17930179
在研究了sqlite3的异步之后,我改变了部分代码,利用sqlite3模块的回调,来调用下一个函数。也就是我引入了Promise.每一个dao层需要同步的方法,我都会返回Promise,外部执行完第一个方法后,可以根据需要传入下一个要调用的函数。
使用promise需要注意的是this的指针的作用域。
目前这个bug已经通过引入promise并修改代码从线性执行为promise形式的链式调用,成功解决
我在main进程中创建菜单的时候增加了console.log,想在idea的控制台打印相关的日志,但是没有生效。
经过查询资料得知.
main进程调用console.log有bug,目前只能打印指定的字符集,中文不能打印。
原issue地址:
SimulatedGREG/electron-vue#605
按照electron-vue中文教程中的教程设置了快捷键,说是要给菜单项传入一个字符串。
于是我传入了这个字符串,但是这种方法,快捷键并没有生效。
于是我又找问题所在,发现这个中文网的教程有歧义。
官方的文档中,描述electron中菜单的快捷键,通常是两种设置方式,
1.app内全局注册.
2.利用web页面的window去注册快捷键.
我之前开发的易语言里面,也有这样的设置。易语言的菜单设计是有一个专门的管理工具的,这个管理工具也是说可以设置快捷键,但其实就是在菜单上显示一些字符串,按下对应的快捷键并没有卵用!
注册快捷键要用全局监听的方式,这就导致了即使不在app的窗口内按下快捷键,也会被监听到。
我之前写的易语言的cmdHelper里面就遇到了这个问题,就是快捷键冲突。我定义的快捷键,确实可以触发某个菜单,但是我这个app只要挂在后台,其他app(比如chrome),就无法监听到我的快捷键,这就是快捷键冲突。
所以我认为electron中,自然也无法避免这个问题。不过electron这个还是和易语言有些区别,即使你指定了菜单快捷键的字符串,但是这个字符串没有再全局快捷键中注册,菜单是不会显示这个字符串来产生歧义的,这就导致另外一个现象,看起来就是设置菜单项快捷键的设置不生效,但其实是没有注册快捷键。
所以,我修改了代码,先全局注册快捷键,再给菜单指定相应的快捷键。
但是我想这样可能会衍生出跟易语言一样的问题,就是快捷键冲突。所以我决定实验一下。易语言中快捷键冲突我暂时没有解决方案,因为找不到局部注册快捷键的方式,所以的组件对键盘按下,都没有反应。这也是我很不爽易语言的原因,因为碰到问题了,解决不了,连个替代方案你可能都找不到,要么开发代价很大,要么就只能开发出有bug的代码。而electron不同,他没有组件的概念,他的渲染是由浏览器负责的,我可以很方便的修改页面的形式,也可以衍生出很多解决方案,比如快捷键冲突,我可以把快捷键局部绑定到页面上去。
先试一下快捷键,然后把冲突了快捷键改掉。
在修改代码的过程中,还碰到了一个恼火的问题,代码的执行顺序和this指针的引用。
我发现自定义的对象,只要对象所处的环境变化,this也会发生改变,比如指向顶层undefied目前我是解决了。但是还是搞不懂this的使用。
然后我发现,即使全局注册了快捷键,也并不管把菜单和这个快捷键自动关联起来。这也就是说,写入快捷键提示是可以的,全局绑定快捷键也是可以的。但是electron不会自动关联两者,这就跟我前面描述的有冲突,但是还是不知道为什么写个快捷键提示也会不成功。
做了个查找功能,想在按下快捷键打开查找框后,查找框自动获取焦点。
我调用了element-ui提供的api,使用this.$refs去调用这个组件来获取焦点。但是element-ui没有鸟我。
我还纠结是不是this.$refs有问题,又去官网查vue.js的api,发现人家用的是this.$ref,然后我又换成this.$ref调用,还是没有鸟我,我把this.$ref打印出来一看,undefind。
然后又把this打印出来一看,只挂在了$refs。
我瞬间无语了,官网说$ref是在当前组件掉的,$refs是在父组件调的,官网的文档都靠不住?
于是我又改成this.$refs来调,组件是找到了,但是还是没有获取焦点。
我就想,这他么不会又被element-ui给忽悠了,文档告诉你这么个API,不管用?
于是我又写了个原生的input去获取焦点,成功了。
我人就不好了。
可能跟组件的可视化有关,因为我是先改变element-ui input的可视再获取焦点的,可能element-ui有动画,所以导致先获取焦点,再可视化导致焦点的丢失也是有可能的,就跟之前脏数据的读取bug一样。
经过一系列的资料查找,终于有了解决方案,使用vue的.$nextTick,在组件全部刷新完毕后,在nextTick的回调中去获取焦点就可以了
下面给出参考的资料
正确理解使用Vue里的nextTick方法
https://segmentfault.com/q/1010000011481239
http://www.flowerboys.cn/VueJs/2017/0614/99.html
在之前的代码中,我已经通过MenuFunc.js文件创建了窗口的上下文菜单,菜单事件触发后也成功的将主进程读的数据显示到渲染进程。
但是刚才写着写着再运行,页面就发白了,什么也加载不出来,electron自动加载的开发人员工具也就是F12就抛出了一个错误,说MenuFunc.js中Menu is not a constructor。
这我就很郁闷了,菜单在之前的代码里都创建成功了,
下面就是代码
// 定义菜单项的功能
const menu = new Menu()
为何突然说Menu不是构造函数呢?
我想着太奇怪了,之前都可以拿构造函数创建菜单,突然又说不行了。
于是我检查了代码的历史记录,发现并没有改动什么东西。
只是加了一些用于菜单被点击后发送事件的事件名常量,常量应该不会影响我的代码运行啊
。
检查了许久,我看着F12的控制台错误发愣,突然意识到了某种东西。
我为了保证渲染层和主进程的事件名一致,把在MenuFunc中定义的事件名常量用import的形式导入到了渲染层。
而import对导入的js是使用单例模式的,这也就是说,在渲染层加载页面的时候,就会调用MenuFunc中创建菜单的Menu构造函数创建菜单。而很明显,Menu模块是不能在渲染层调用的,这也就直接导致了渲染的失败。
而之前的代码没有这样做,只是在主进程中创建菜单。
也就是说,我尝试着在渲染层导入一个js,这个js本来是在主进程中加载的,创建菜单和定义常量都不会报错,但是渲染层又加载了一次这个js,渲染层也尝试着创建这个menu对象,然后就在开发人员工具中抛出了Menu is not a constructor这个错误。
我将渲染层引入MenuFunc.js文件改了名字,再启动,代码没有再报错。
这个bug其实是代码逻辑引起的,这也证实了主进程的模块是不能在渲染层调用的申明。
这个逻辑引起的bug这很好解决,只要把在MenuFunc定义的事件常量移到一个普通的js文件,然后渲染层和主进程各自引用这个js或者将这个常量共享就行了。
大致情况是这样,想让输入框中按下回车后对数据库进行模糊查找。于是使用了element-ui中的输入框。庵后使用v-on绑定key-up事件,但是发现事件并没有被触发。
首先想到的是是否是语法写错了,毕竟有很长时间没有玩vue了,不知道是否会有语法的更新。经过查找,语法确实有更新,但是我使用的electron-vue脚手架搭建的vue环境版本是可以对上的。也就是说并不是语法问题。
于是我又去查找electron-vue的相关问题,想看看是不是有这类问题的解决方案。electron-vue推荐了在渲染层绑定快捷键的方法,是使用window对象添加事件监听器。
我尝试了以下,发现页面是可以接收keyup事件的,但是element-ui的相关组件上依旧没有事件的触发,触发的是window上绑定的keyup事件。于是我又尝试着绑定了click事件,发现依旧不触发。
这是只剩下几种可能性,
1.keyup事件被electron拦截去处理了,但没有处理事件的冒泡,所以webContents上没有接收到keyup事件。
2.webContents上接收到keyup事件,但是被element-ui拦截了。
第二种问题是比较麻烦的,因为我element-ui文档并没有找到相关的事件是如何触发的,只是element-ui为了实现一个提示输入的功能,已经使用了key-up事件。
我使用了一个普通的input标签,绑定了keyup事件,发现这个input是可以接收到keyup事件的,所以问题就确定了,keyup事件被这个element-ui的组件给拦截了。
这个时候的解决方案也只有两种,1,放弃使用element-ui的组件,使用自定义的组件。2.使用window监听键盘按下事件.
第一种方案代价太大,我使用第二种方案,用原生js手动绑定一个事件监听器就可以了。
先说下大致的问题吧。
主要功能是在启动后读取完sqlite3的数据后,显示到vue的页面。
按照最初的设想,vue是双向绑定的,通常用的最多的就是改变数据后就改变了视图,不需要我们去操作dom。
不用想,vue是属于渲染进程,要读取主进程的数据,就涉及到主进程和渲染进程通讯。
一开始看到了一个electron提供了一个简单的方案,是多进程读取同一块全局变量。于是我就用vue直接绑定了这个全局变量,然后当主进程的菜单被点击后,主进程的菜单点击事件将数据读取出来,塞到这个全局变量里,理论上vue就会刷新视图。
但是并不顺利,vue并没有如我想象的去刷新视图。
于是又参考了下electron进程之间通讯的api,最后决定绕一圈,用事件发射的方式,让主进程读取完数据后,将数据塞到全局变量里,再发送一个事件,渲染进程接收到该事件后将调用某个函数,再把数据读取出来,绑到vue的组件上。这次成功了,但前提这个vue组件的属性在初始化时,不能直接绑定全局变量。
中间还除了一些小bug,比如主进程中弹出的警告框后只有强制退出才能中断程序,不退出不管你的逻辑如何,都会直接走完正常程序,这个bug我到现在也没有想通,是怎么出现的。鉴于我学习的特性,这个问题,恐怕很久都得不到答案。
从目前找到的资料来看,node.js下运行的第三方模块是可以直接运行在electron上。但是也有很多模块需要进行安装才可以。找了很多资料,都没有解决electron使用sqlite3的问题。
直到后来按照下面这偏博客的指导,才有了方向。
第二种方法,前面两步都成功,第三步报错提示没有python。于是我又重新审视了整篇博客,准备安装一个python,再尝试一下.
需要注意的是从官网下载的python2.7的安装包默认不会配置环境变量,但是这个是可选的.
而且,你从cmd中可以看到python安装成功后,idea中的命令行工具并不能识别到这个python命令。
因此我选择重启idea
很明显重启了idea之后也没用。
然后我又重试着使用管理员权限打开idea。终于在idea的命令行端进入了python。
然后我又重新尝试着编译sqlite3的electron版本的dll,但是报了一个错误。
这个错误很常见,连接超时,很明显是在预编译的时候从美国的服务器上下载文件,然后由于网速问题,这个服务又他娘的挂掉了。这种情况下,基本不要慌,重试几次就ok了。
然而重试了好几次,都会中断这个编译过程。我意识到这样不行。
在查询资料后使用如下命令解决了问题.
npm config set ELECTRON_MIRROR http://npm.taobao.org/mirrors/electron/
设置electron镜像指向淘宝.
并关闭了sockwindow(一个全局的http代理翻墙软件)。
再尝试编译,就成功了。
以下是相关的资料.
https://newsn.net/say/electron-install-sqlite3.html
刚开始用这个vue-electron 的模版开始编写APP的时候,
是跟着官方的教程,使用vue-cli工具下载的一个vue-electron模版。
在构建项目初始结构的时候,一路都使用了默认设置,然默认的项目模版是使用eslint的。
这个eslint就是问题所在,如果我们确认我们编写的JS代码语法没问题,然而修改仍然不生效。请先尝试在这个js文件中关闭eslint的检查。
这个做法很简单,加上/* eslint-disable */这个注释就可以了
(我通常加载头部,因为这样可以让eslint 跳过对头部的空变量或者空引用检查)。
查看项目的目录结构和源码,可以知道src/main/index.js下是根据运行/开发环境决定是加载远程的vue页面还是加载本地已经打包好的vue页面。
也就是说我们开发时,如果修改了vue的某个页面/组件,只需要electron刷新或者reload就可以看到修改的效果了。
即使这刷新/reload的动作,vue-electron也不需要你动手,基于node 的 热更新 已经被大神们移植为到electron上面了,因此,当我们修改web页面,我们并不需要重启整个项目,跟在node上开发vue的流程是一样的。这也是我使用vue-electron的愿景之一。
而src/main/index.js 是运行在electron 主进程中的,这与vue+node采取的热更新开发不同,他的开发类似于热部署。对主进程的每次修改都要重启整个electron。
因此eslint的语法检查所引发的错误可能会中断整个打包js的过程。electron的启动后很有可能因为文件不完整而导致加载不起来,或者加载的仍是上一个打包成功的主进程的js文件。
因此,关闭eslint 可能会给予我们一个更好的开发体验。
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.