手摸手Electron + Vue实战教程(五)

1369次阅读  |  发布于4年以前

上一篇我们已经完成了数据持久化,使得我们创建的 Markdown 笔记得以保存,这一篇我们就开始实打实地创建 Markdown 笔记了。

不过我们先来优化一下之前数据库初始化的地方:

数据库初始化变更

其实就是加了个命名空间,创建多个数据存储,这样改造是为了后续开发其它功能的时候可以方便存储数据,而不用跟 Markdown 文件的存储混合在一起。

1 创建文件

先把上一篇对数据库写的增删改查伪代码统统删掉,现在已经用不上了,如果大家对 nedb 的具体 api 还不清楚,可以直接去官网浏览即可,虽然我们是用了nedb-promises插件库,但其实 api 是一致的。

在页面交互上,点击“+”号的按钮出现下拉菜单,直接创建文件:

file-search组件中调用$emit方法create,这里执行新增文件的逻辑,在 methods 中编写函数新增 Markdown 数据,我们上一篇已经写过 demo 了,非常简单:

template中的代码也很简单:

2 获取文件列表

我们创建了新文件,那肯定得在左侧的列表菜单展示出来,列表是从nedb数据库中获取是毋庸置疑的了,那么我们什么时候去获取这个数据呢?每次初始化程序和创建文件、编辑文件,还有后续我们导入文件,一旦这几个状态改变的时候我们都需要重新从数据库里面拿取最新的文件数据来生成列表。好,搞起!

获取文件列表

看图说事,新增 getFileList 方法,这里使用async/await的写法,懂的自然懂,不懂请自行百度了。

sort是 nedb 自带的排序api,参照有道云笔记我们可以看到,最新编辑的永远是排序在最顶部的,所以我们设置 updatedAt: -1 来根据修改时间来倒序排列。方法接收一个query搜索条件的参数,后面我们做搜索列表的时候会用到的。

这里获取到列表数据后我就直接格式化时间了,渲染的时候就直接无脑渲染即可。时间格式化用的是dayjs,只有2kb的大小,可谓短小精悍强大得不可理喻:

无脑式安装,这步操作太简单了我真的不想写,但还是走流程写一下吧,下次我再也不这样了(多么熟悉的话语……):

yarn add dayjs // 安装

import dayjs from 'dayjs' // 直接引入使用

mounted钩子中直接调用刚才的方法:

this.getFileList()

到这里左侧文件列表已经可以出来了:

文件列表

我们来改造一下之前的FileSearch搜索笔记组件,我们需要给它添加一个执行搜索的 $emit :

然后在 Home.vue 页直接调用,加入 vue 的修饰符@keyup.enter可以直接回车键执行搜索:

handerSearch方法就可以调用我们刚才的获取列表方法了,如果搜索条件为空的时候就直接return结束,否则就传入需要搜索的标题名称,nedb 支持正则搜索,我们直接动态生成正则表达式,就可以实现搜索笔记的功能了,i表示搜索不区分大小写,是不是 So easy,对正则有疑问的可以看一下这里哦:https://www.w3school.com.cn/jsref/jsref_obj_regexp.asp。

如此实现搜索是没问题的了,但是当我们清空搜索条件的时候却并没有刷新笔记列表,所以我们要加上监听,当清空搜索条件的时候重新刷新列表一遍:

dom 代码

js 代码

至此,搜索功能就大功告成了。

3 组件优化

现在回到我们原型中,打开有道云笔记,可以看到每次新建笔记后,它会自动在左侧列表,同时也在编辑区更新标题和内容。但是现在我们点击“+”按钮创建文件左侧列表并没有更新,右侧编辑区也没有默认打开刚创建的文件,我们需要改造一下fileCreate()方法:

// 创建文件
fileCreate() {
  const defaultFile = { title: '无标题笔记', content: '' }
  this.$db.markdown.insert(defaultFile).then(async () => {
    await this.getFileList()
    const [firstFileItem] = this.fileList
    this.fileItem = firstFileItem
  })
}

FileEdit 组件

在新增数据成功后,我们重新获取一遍列表文件,并且把获取到列表的第一个数据赋值给fileItem,这个fileItem就是我们需要传递给右侧文件编辑组件FileEdit的数据。这样每次新建笔记后,左侧列表就可以实时刷新,右侧编辑区也能实时更新到我们刚新建的笔记了。

到这里了好像有个坑了,之前埋下的一个坑点……

FileEdit已经接收到了我们fileItem的赋值,但是标题却依旧没有更新,这是因为我们初始化的时候已经传了个空标题,然后又在 data 中赋值给变量currentTitle,这样会导致的问题是它永远只展示了第一次传进来的数据,后面的它就不更新了,所以这里我们需要给 props 的title加个监听,就可以完美解决新建笔记后编辑区标题不更新的问题了:

FileList 组件

左侧笔记列表还缺少一个高亮选中的状态,有点 vue 基础都知道怎么写了,给个点击事件添加class样式就 ok 了:

但是我们不仅要在点击的时候高亮,创建新笔记的时候会默认打开第一个笔记,这时候第一个笔记在列表中应该是高亮的,所以FileList组件的高亮状态不仅要在内部可以操作,同时外部也需要可以操作,这时候其实我们接收个propswatch一下就搞定了,详细原理跟FileEdit组件中是一模一样的:

组件引用那里我们需要加上一个参数active

新增笔记的时候再把activeIndex手动设置为0:

这样就可以指哪打哪,实现在组件内部点击哪个就高亮哪个,同时也可以在外部想设置哪个高亮就设置哪个。

4 实时保存

现在右侧的编辑区域其实已经是可以完整编辑 markdown 了,但是却还无法保存,重启项目后我们编辑的 markdown 全都没了。

有道云笔记的文件保存触发是只要一切换了当前打开的文件就自动保存,或者手动ctrl + s保存,我们现在不走这个机制,标题的话只要失焦blur就保存,内容区直接就是实时监听输入的内容然后立刻保存,99%杜绝什么电脑突然断电而导致的文件文保存丢失问题(还有1%是玄学问题……)。

既然方案已经有了,那就速度搞起吧!!

标题保存

FileEdit组件中,在标题栏中监听失焦blur事件,然后通过$emit自定义事件titleBlur将修改过的标题抛出去:

Home.vue文件中引入组件部分写入@titleBlur执行修改数据库中存储的标题:

根据id修改数据库数据,title: { $ne: title }的意思是如果标题是相同的则不修改,修改成功后,如果当前高亮的不是列表中的第一个笔记,则需要重新获取列表最新数据,然后将高亮activeIndex设置为第一个:

内容保存

只要内容有更新了,则立即执行保存,我们直接监听change事件即可:

我们在获取列表数据的时候,要添加一个字段备份,当修改后的数据跟备份的数据一致时,则不进行保存,这个操作也是为了切换列表笔记时不会执行保存的操作:

现在貌似修改标题和修改内容的两个方法中有大量重复代码,这里可以把它们抽离出来:

防抖和节流

现在保存的功能实现倒是实现了,但是每次修改一个字都会执行一次保存,写一篇一万字的文章就得保存 1W 次,想想就很可(sha)怕(bi)……这个时候防抖节流就应该出来了。

函数防抖和节流,这个知识点面试中被问的概率也是比较高的,大家不明白的赶紧去弄清楚哈,我在这里就不多赘述了,懂的自然懂哈。此时只要稍微修改一下我们保存内容的函数就可以了,看看最低级的防抖写法:

5 小结

能看到这里,相信有不少人应该也看得出,这一篇内容的实现其实不是最优代码,无论在标题的保存还是内容区的保存。在获取笔记列表后新增一个字段来备份数据,这个一旦笔记多了,会大大造成内存的浪费,electron本来就吃内存,加上这个低端机估计就卡得不行了,然而我并不打算优化这一块,嗯,至少目前是木得时间来优化了,就交给各位有兴趣的大大咯。

项目 github 地址:https://github.com/mengdebiao/vue-electron-notes

Copyright© 2013-2020

All Rights Reserved 京ICP备2023019179号-8