给 hugo 站点添加搜索功能

给站点添加搜索功能有很多种方式,不管是哪种方式,原理都是先对内容建立索引,然后使用一个搜索引擎根据索引进行查询。本文我们就用纯前端的方式来给 hugo 静态站点添加搜索功能。
CC-BY-SA-4.0

前言

对于数据库驱动的网站,我们可以执行SQL查询关键字进行搜索;而对于静态站点,我们需要首先生成索引文件,然后用一个搜索引擎进行查询。

这里我们使用一个纯前端的搜索引擎 Lunr

生成文章列表数据

因为我们的网站是用 hugo 搭建的静态网站,所以我们要在 hugo 构建时生成 json 格式的文章列表。

创建json模板

创建模板文件layout/_default/search.json,内容如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
{
    "results": [
        {{- range $index, $page := .Site.RegularPages }}
            {{- if $index -}}, {{- end }}
            {
                "href": {{ $page.Permalink | jsonify }},
                "title": {{ $page.Title | jsonify }},
                "body": {{ $page.Content | plainify | jsonify }}
            }
        {{- end }}
    ]
}

应用数据模板生成文章列表数据

默认情况下,我们只有数据模板是不会自动生成数据的,我们需要显式使用这个模板。

首先,创建一个 search.md 文档:

1
hugo new search.md

我们不需要这个文档的内容,我们只是使用它的front matter来指定输出格式,如下所示:

1
2
3
4
---
layout: search
outputs: ["JSON"]
---

我们指定了这个文档的模板采用我们之前创建的数据模板文件search,输出格式指定为JSON。 这样在 hugo 构建时就会输出一个search/index.json文件,内容就是我们网站的所有文章生成的一个 json 文件。

构建索引文件

在主页使用axios获取文章列表:

1
2
3
axios.get("/search/index.json").then(response => {
    window.ArticleList = response.data.result
})

构建lunr的索引文件:

1
2
3
4
5
6
7
8
const LunrSearchIndex = lunr(function () {
    this.ref('href')
    this.field('title')
    this.field('body')
    window.ArticleList.forEach(article => {
        this.add(article)
    })
})

执行搜索

这一部分就比较简单了,我们有了文章的索引直接调用search就可以了:

1
2
let searchText = 'search text from input'
let resultList = LunrSearchIndex.search(searchText)

关于lunr支持的搜索语法,可以查看Lurn#Search

Comments