归档 标签 友链 关于

给 Gridea 博客增加搜索功能

使用 Gridea 将近一个月了,从 UI、功能、扩展性等各方面来说几乎完美,作为静态站点生成器来说真的很强大了。也正因为是静态博客,所以想支持搜索功能的话是有一定难度的,大家基本都使用第三方网站解决,如 Google ,百度等,也有专门支持小型静态网站的 Algolia DocSearch,但是从接入流程和最终效果来看,我并不满意。

好在 Gridea 有将整站的数据以 html 的形式发布出来的 API,所以理论上自己实现一个搜索功能是可以做到的。只要获取到包含所有文章的标题、内容以及链接,那么搜索的功能基本上就能够实现了。

我打算实现的最终效果是在搜索框中输入关键字,跳转到一个搜索结果页面,罗列出包含关键字的所有文章信息,并且能够预览文章内容,关键字高亮等。

由于每一次搜索都是遍历整站内容,所以在文章数量达到一定量级后,网络请求就很费时,所以考虑做一个本地缓存,在第一次请求后将内容缓存到本地,之后的查询就可以直接从本地读取。但如果网站更新了还从缓存读取的话,搜索到的内容就与最新内容不一致,所以在网页上加了一个网站更新时间的标记,这个时间是 Gridea API 提供的。本地写入缓存时将这个时间标记一并保存到本地,如果网页上的时间标记与缓存的时间标记不一致了,那就重新请求并更新缓存,保证数据的一致性。

实现过程大体分为 4 个步骤:

  1. 输出包含全站文章、标题和链接的 JSON 字符串,用以搜索和跳转;
  2. 将输入的关键字与文章进行遍历匹配,得出包含关键字的文章链接、标题等;
  3. 缓存检查与更新;
  4. 渲染搜索结果页面;

搜索算法相对较为复杂,好在有开源的第三方前端搜索工具 Fuse.js,解决了一大难题。只需要简单的配置,把待搜索的 Array<Object> 和关键词传入函数就能够得到搜索后的结果,还能得到关键词的位置,用作高亮显示。

虽然能搜索出来,得到想要的结果,但是显示也很难处理,如果只是考虑我自己的博客,那么一切 OK,操作 DOM 节点完全可以解决。但我想要的效果是在别人几乎不写代码的情况下使用我写的搜索功能,那么就要考虑更好的办法了。

Gridea 是基于 ejs 模板解析实现的,能不能也用 ejs 来实时渲染结果呢?答案当然是可以的,ejs 不仅支持在服务器端即 node 环境下解析,还支持在浏览器端实时解析渲染,这样就可以极大地减少主题开发者的使用难度,完全按照原来的方式去写搜索结果页面,0 附加学习成本,岂不美哉?只不过搜索结果页的模板放在网页的静态资源目录,通过 ajax 请求就行了。

既然可以按照原来的配置方式,那么加入 Gridea 的 API 也是有必要的了。因此我新增了一个输出全站信息 API 的模板页,只是不包含文章内容。至于为什么不和之前的 API 放在一个文件里呢?因为当文章数量上来以后,这个文件就会变得很大,分离出一个独立的文件显得更好。通过 Fuse.js 得到搜索结果后,将相关的数据输入到 ejs 模板中,直接输出结果列表然后 append 到相应的 DOM 节点上,主题开发者就可以完全按照官方的 API 去配置搜索结果页,比如添加文章发布时间、tag 等,甚至可以复用主页使用的文章列表模板。

Gridea 的搜索插件已经开源到 GitHub 上了,虽然技术不复杂,但是考虑了性能上的优化和使用的简便性,过程很有趣,最终效果我也很满意,Gridea 的用户们可以考虑了!

最后,来个效果图:


· 转载请注明 https://tangkaichuan.cn/search-for-gridea-blog/