📢 新文章推送 · 每周更新优质内容 · 订阅更新 →
向下滚动
技术笔记

静态博客全站搜索功能实现方案

AI 智能总结

静态博客搜索的难点

静态博客的所有页面都是预生成的 HTML 文件,没有后端服务器和数据库,因此无法像动态网站那样执行 SQL 查询来实现搜索。常见的静态站搜索方案有三种:

  1. 第三方服务(Algolia、DocSearch)
  2. 客户端全文搜索库(Fuse.js、Lunr.js)
  3. 自建 JSON 索引 + 前端搜索

本文介绍的是第三种方案:在 Hugo 构建阶段生成包含全站文章内容的 JSON 索引文件,前端 JavaScript 加载该索引并在浏览器端完成搜索。

Hugo 端:生成 JSON 索引

首先在 hugo.toml 中配置首页输出 JSON:

1[outputs]
2  home = ["HTML", "RSS", "JSON"]

然后在主题的 layouts/_default/index.json.json 中创建模板:

 1{{- $pages := where .Site.RegularPages "Type" "in" .Site.Params.mainSections -}}
 2[
 3  {{- range $index, $page := $pages -}}
 4    {{- if $index }},{{ end }}
 5    {
 6      "title": {{ $page.Title | jsonify }},
 7      "url": {{ $page.Permalink | jsonify }},
 8      "date": {{ $page.Date.Format "2006-01-02" | jsonify }},
 9      "content": {{ $page.Plain | truncate 500 | jsonify }},
10      "categories": {{ $page.Params.categories | jsonify }},
11      "tags": {{ $page.Params.tags | jsonify }}
12    }
13  {{- end }}
14]

这段模板会在站点根目录生成 /index.json,包含每篇文章的标题、URL、日期、摘要内容和分类标签。

前端:搜索逻辑实现

前端搜索的核心流程:

  1. 加载索引:页面初始化时 fetch 加载 /index.json
  2. 监听输入:监听搜索框的 input 事件
  3. 执行搜索:在内存中对标题和内容做关键词匹配
  4. 渲染结果:动态生成搜索结果列表的 DOM 节点

搜索算法

最简单的实现是对每条记录的 titlecontent 字段做字符串包含匹配:

1function search(keyword, records) {
2  const lower = keyword.toLowerCase();
3  return records
4    .filter(record =>
5      record.title.toLowerCase().includes(lower) ||
6      record.content.toLowerCase().includes(lower)
7    )
8    .slice(0, maxResults); // 限制最大结果数
9}

如果需要更好的搜索体验,可以引入 Fuse.js 库实现模糊匹配:

 1const fuse = new Fuse(records, {
 2  keys: [
 3    { name: 'title', weight: 2 },    // 标题权重更高
 4    { name: 'content', weight: 1 },
 5    { name: 'tags', weight: 1.5 }
 6  ],
 7  threshold: 0.4,  // 模糊度阈值
 8  distance: 100
 9});
10
11const results = fuse.search(keyword);

搜索框 UI

搜索框通常放在导航栏或侧边栏。点击或按 Ctrl+K 快捷键弹出搜索面板:

1<div class="search-overlay" id="search-overlay">
2  <div class="search-panel">
3    <input type="text" id="search-input"
4           placeholder="搜索文章..."
5           autocomplete="off">
6    <div class="search-results" id="search-results"></div>
7  </div>
8</div>

键盘快捷键

增强用户体验的键盘操作:

快捷键操作
Ctrl + K / Cmd + K打开搜索
在结果中上下移动
Enter打开选中文章
Escape关闭搜索

性能优化

索引文件大小控制

如果文章数量较多(>100 篇),JSON 文件可能很大。优化策略:

  • 内容截断:每篇文章只保留前 200-300 个字符
  • 移除不必要的字段
  • 开启 Gzip:Nginx 或 CDN 层开启 gzip 压缩,JSON 文件压缩率通常 >80%

搜索结果数量

通过 maxResults 限制返回数量(默认 30),避免渲染过多 DOM 节点。同时使用防抖(debounce)减少搜索频率:

1const debouncedSearch = debounce(function(keyword) {
2  renderResults(search(keyword, records));
3}, 200);
4
5input.addEventListener('input', function() {
6  debouncedSearch(this.value);
7});

总结

基于 JSON 索引的前端搜索方案具备以下优势:

  • 零成本:无需第三方服务订阅费用
  • 离线可用:索引加载后可离线搜索
  • 完全可控:搜索逻辑和 UI 都可以自定义
  • 构建时生成:索引随 Hugo 构建自动更新,是最新的内容

本站搜索功能即采用此方案,支持全站文章标题和正文的即时搜索,最大搜索结果数可配置,同时支持键盘快捷键操作。

6 / 16
版权声明

本文作者 Lumin

本文链接 https://www.zhengquan.xyz/tech/static-site-search/

许可协议 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明出处!

请作者喝杯咖啡 ☕

  • 微信打赏
    微信支付
  • 支付宝打赏
    支付宝
点击按钮查看打赏二维码
🎁 推荐工具
试试这些实用在线工具,提升工作效率
前往工具集 →

留言评论

期待你的想法

评论加载中