· 分享 · 3 min read
给静态博客加一个命令面板搜索
用 Fuse.js 在构建期生成索引,零依赖后端实现按 / 呼出的模糊搜索。
昨天把 srz.cc 的主题换成 AstroWind 之后,原来的站内搜索丢了。全文搜索用 Pagefind 补了一个 /search 页面,但日常最常用的其实是另一件事:记得文章标题里有个词,想立刻跳过去。这种需求不值得一个整页,我更想要 macOS Spotlight 那种体验——按一个键,弹框,打字,回车跳转。
思路:构建期索引 + 运行时模糊匹配
静态站没有后端,但文章数量通常在几百篇以内,把标题、标签、分类、摘要打包成一个 JSON 完全放得下。实测 srz 的 18 篇文章索引只有 3.7 KB,比一张图都小。于是流程变成:构建脚本扫描 content 目录生成 search-index.json,页面加载时 fetch 它,把数据灌进 Fuse.js 做客户端模糊匹配。不依赖搜索服务,不占任何运行时资源,CDN 缓存友好。
astro build && node scripts/build-search-index.mjs && pagefind --site distbuild-search-index.mjs 做的事情很朴素:解析每篇文章的 frontmatter,剔除 draft,输出扁平数组。权重交给 Fuse 配置:title 0.6、tags 0.2、category 0.1、excerpt 0.1——标题命中最重要,其余是补充信号。
交互细节才是灵魂
组件本身不到两百行,体验全靠几个细节撑起来:按 / 或 Ctrl/Cmd+K 呼出;呼出时先 preventDefault,避免把斜杠打进输入框;上下键移动光标、回车跳转、Esc 关闭;结果列表里分类、日期、标签排成一行元信息。中文不需要分词——Fuse 的模糊匹配对「分类」「搜索」这种子串命中一样有效。 还有一个容易漏的点:焦点管理。弹框打开时要记住之前聚焦的元素,关闭后把焦点还回去,键盘用户会感谢你。
和 Pagefind 的分工
两套搜索并存但不冲突:命令面板管「找记得标题的文章」,毫秒级响应;/search 全文页管「找正文里提过某个词」,靠 Pagefind 的倒排索引。前者高频轻量,后者低频重量,正好互补。 如果你的博客也是静态生成器产物,这个方案值得抄:一个构建脚本、一个组件、两个按键绑定,比装任何搜索服务都省事。
