这个博客没有后端,却能站内搜索。静态站既没有数据库也没有服务端接口,搜索这件「天生需要查询」的事,是怎么做到的?答案是:把索引在构建期生成好,查询全放到浏览器端做。
思路:索引前置
动态站的搜索是「用户输入 → 后端查库 → 返回结果」。静态站没有后端,于是换个思路:在生成网站的时候,把所有文章的标题、正文、链接打包成一个 JSON 文件(本站用 hexo-generator-searchdb 生成 search.json),随站点一起部署。浏览器加载这个 JSON,搜索就在前端内存里完成。
1 | [ |
最朴素的实现
数据量不大时,直接 includes 子串匹配就够用:
1 | let data = null; |
本站正是这么做的:弹出搜索框时才懒加载 search.json,输入时实时过滤,取前 10 条。几十上百篇文章的规模,这种暴力匹配在现代浏览器里毫秒级完成,体验完全够。
几个体验细节
- 懒加载索引:别在首页就下载
search.json,等用户真的打开搜索框再 fetch,省首屏流量。 - 防抖:输入事件触发很频繁,高频场景可以加
debounce限流;但纯内存子串匹配其实很快,可不加。 - 结果高亮:把命中的关键词用
<mark>包起来,结果一目了然。 - 截断摘要:正文很长,结果里只展示命中位置附近的一小段。
什么时候需要更专业的方案
子串匹配有两个短板:一是不分词(搜「前端性能」不会命中「前端的性能」),二是数据量大时 JSON 体积和遍历成本都上来了。这时可以升级:
- 倒排索引:预先把「词 → 出现在哪些文档」的映射建好,查询时查词表而非遍历全文。
Fuse.js、Lunr.js、FlexSearch都是前端可用的库。 - Pagefind:专为静态站设计,构建期分片建索引,查询时按需下载分片,万篇文章也不卡。
- Algolia:托管搜索服务,免费额度够个人博客用,但引入了外部依赖。
小结
静态站搜索的精髓是「把索引提前到构建期,把查询下放到客户端」。小博客用一个 search.json + 子串匹配就够优雅;规模大了再上倒排索引或 Pagefind。无后端不等于没搜索,只是把计算挪了个位置。