惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

爱范儿
爱范儿
Security Latest
Security Latest
NISL@THU
NISL@THU
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
C
Cybersecurity and Infrastructure Security Agency CISA
Cloudbric
Cloudbric
T
Threat Research - Cisco Blogs
大猫的无限游戏
大猫的无限游戏
C
CXSECURITY Database RSS Feed - CXSecurity.com
阮一峰的网络日志
阮一峰的网络日志
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
雷峰网
雷峰网
C
Cisco Blogs
V
Vulnerabilities – Threatpost
S
Security Archives - TechRepublic
V
Visual Studio Blog
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
J
Java Code Geeks
D
Darknet – Hacking Tools, Hacker News & Cyber Security
Know Your Adversary
Know Your Adversary
博客园 - 叶小钗
腾讯CDC
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
P
Privacy International News Feed
P
Palo Alto Networks Blog
博客园_首页
V
V2EX
WordPress大学
WordPress大学
Schneier on Security
Schneier on Security
月光博客
月光博客
博客园 - 司徒正美
Google DeepMind News
Google DeepMind News
TaoSecurity Blog
TaoSecurity Blog
博客园 - 聂微东
酷 壳 – CoolShell
酷 壳 – CoolShell
人人都是产品经理
人人都是产品经理
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
博客园 - 【当耐特】
The Cloudflare Blog
罗磊的独立博客
美团技术团队
N
News | PayPal Newsroom
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
Last Week in AI
Last Week in AI
K
Kaspersky official blog
Google Online Security Blog
Google Online Security Blog
S
SegmentFault 最新的问题
Application and Cybersecurity Blog
Application and Cybersecurity Blog
T
Tailwind CSS Blog

优世界

OpenWrt 路由器改纯 AP 模式记录(Cudy TR3000 + 中兴 F50) Ubuntu 24.04 安装 Zabbix 8.0 全记录 我的静态博客动态化方案 Claude Code 启动脚本 我的5G路由器方案:中兴F50+cudy tr3000 256MB 还是弃用了使用多年的全拼输入法 临走前一份襄阳牛肉面 EdgeOne Pages 部署 Twikoo 评论 一个朋友圈风格 Hugo 主题 搓了一个仿朋友圈的Hugo主题 一个人烧烤被拒单了 周末闲暇时间翻修了一下博客 我把Vercel换成了EdgeOne Pages 博客友链实时健康监测方案 Artalk评论区接入AI摘要的尝试 给Hugo博客添加瀑布流相册功能 Artalk评论系统实现段落评论功能 为什么我觉得网页昼夜切换那么重要 博客六周年:从折腾到回归平淡 如何hugo静态实现友联朋友圈功能 脂溢性皮炎的烦恼 还是放弃了iPhone16e 米环勿扰同步问题 除草日记 Hugo使用GitHub Action自动刷新多吉云CDN缓存 迁移博客至hugo 添加ikun摆件 parsec远程软件报6023错误 win11右键菜单改回win10方法 主板电流声 主机配置单 一次点亮 访客体验优化 博客除草 老爷机升级 完善主题 家乡随拍 襄阳唐城 进厂日记 苏州一日游 四月随笔 评论置顶 Time Taker 近来二三事 感谢哥哥给的网站 又又又双叒叕换主题啦 生活篇:疫情放开前后的这些日子 .cc域名后缀续费即将涨价 Apple Watch Series7 三个月的使用体验 2022年·襄阳第一场雪,谨以此片记录 记一次莫名其妙ddos攻击,致谢天御云高防cdn 毕业篇:不出意外,这是我最后几个月的大学生活啦 毕业纪念篇:图书馆 生活篇:我的三年封校生活 没错,我回来了,湖北管局一天不到通过备案,强的! 因需要更换备案主体,临时关闭博客通知 记录篇:将笔记本联想小新pro13网卡由螃蟹网卡换成AX210网卡 主力机由荣耀20切换到iPhone13使用半年的感受 生活篇:温馨提示假期余额不足,浅浅总结一下这个暑假 typecho实现QQ头像用户评论加密,注意:pigeon,twitter用户有彩蛋哦! 生活篇:离校,暑假,租房,面试,致那些日子的琐碎事 生活篇:我跳绳的那些日子,谈谈自己的变化 去除typecho1.2.0正式版的后台提示更新bug 利用fontspider压缩博客字体大小,达到加快访问速度 iphone快捷指令发布动态说说,支持大部分typecho主题 寒假二三事 2022,除夕过后的那些事 2022,致我的春节回忆录 祝大家元旦快乐,给自己的博客加一个对联和灯笼 更换掉jsdelivr,改用腾讯云静态网站托管,网站速度比之前提升了不少 这次的落日比较有特色,西边摇摇欲坠的咸鸭蛋 盘点一下建站以来所注册的域名,我居然注册了一堆学费米 可惜不能一直做小孩子,总要长大,不知道实习生活会是什么样子 这组照片的主题,咱就叫它光吧 双十一已经变味了,不知道从什么时候反感双十一了 第一次尝试ai画简笔画,本是给自己设计logo误打误撞画起了简笔画 不用改变图片原地址,实现图片自动转webp格式,速看,一会删 让typecho支持webp格式的图片,告别阿里云oss和腾讯云cos被恶意刷流量的风险 运动会闲暇这几天,简单给大家分享一下日常吧 我又双叒叕换主题,我发现我好像一直在折腾 记录人生第一次洗牙,不得不说感觉真的特别好 我为什么要写博客?这位博主给了我答案 我想,这是一个我人生中最特殊的中秋国庆节 理工的晚霞,拿起相机记录青春的样子 别让抖音支配了你的美好大学生活,尝试做一些自己感兴趣的事 一岁一礼,一寸欢喜,生日快乐,致我的二十岁 2021暑假总结,记录一下这个充实的暑假 Twitter主题设置仿mac UI 语法高亮代码方法 Twitter主题加入加载耗时,访问总量功能 一把过,科二结束! 再次投资科目二,科目二花了400,希望19号一把过吧 宝塔面板设置Typecho伪静态去掉index.php教程 开学倒计时,再见,老家 或许不是没有年味了,只是快乐已经不属于我们这一辈人了 五福开奖,你好,2021 新春快乐!牛年大吉! 祝母校越办越好 军训太痛苦了,希望早点结束 高考加油,相信自己 高考即将来临,老师为我们加油打气
Hugo静态博客如何实现搜索功能
2026-01-28 · via 优世界

最近发现博客文章数量慢慢上来了,有时候想找自己以前写的某个知识点,翻半天都翻不到,确实有点不方便。

其实早就想加个搜索功能了,但看了一圈,像 Algolia 这种第三方服务虽然强大,但配置起来感觉有点繁琐,而且对于咱们这种访问量不大的静态博客来说,是不是有点“杀鸡用牛刀”了?

想了想,还是决定用最简单的方式来实现:直接生成一个 JSON 索引文件,用 JS 在前端搜一下。虽然比较基础,但胜在轻量,而且完全可控。

折腾了几个小时,终于搞定了,顺便把交互做得稍微优化了一下,支持了 PJAX 和暗黑模式。这里简单记录一下实现过程,希望能给同样在折腾 Hugo 的朋友一点参考。

效果展示

为了不破坏页面的简洁感,我把搜索入口藏在了两个地方:

  1. 右下角悬浮工具栏:点那个放大镜图标,会弹出一个搜索框。
  2. 首页“随笔”标题:这个算是个小彩蛋吧。在首页找到“随笔”这两个字,鼠标放上去会有“点击搜索”的提示,点一下就能直接在原地搜索,不用跳转。

实现思路

原理其实非常简单,主要就三步:

  1. 让 Hugo 构建时多生成一个 index.json 文件,里面包含所有文章的标题、链接和摘要。
  2. 前端 JS 通过 fetch 请求这个 JSON 文件。
  3. 根据用户输入的关键词,在 JSON 数据里进行匹配,然后把结果渲染出来。

代码实现

1. 配置 Hugo 输出 JSON

首先在 hugo.toml (或者 config.toml) 里配置一下输出格式,告诉 Hugo 首页除了 HTML 还要输出 JSON。

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

2. 创建 JSON 模板

在主题的 layouts/index.json 创建一个模板文件,定义 JSON 的数据结构。这里我只取了标题、日期、链接和摘要,尽量让文件小一点。

[
    {{- range $index, $e := where .Site.RegularPages "Type" "post" -}}
    {{- if $index -}}, {{- end -}}
    {
        "title": {{ .Title | jsonify }},
        "date": {{ .Date.Format "2006-01-02" | jsonify }},
        "permalink": {{ .Permalink | jsonify }},
        "summary": {{ .Summary | plainify | jsonify }}
    }
    {{- end -}}
]

这样每次 hugo 构建的时候,网站根目录就会生成一个 index.json

3. 前端 JS 逻辑

逻辑主要在 main.js 里。为了提升体验,我做了一些小优化:

  • 懒加载:不会一打开网页就下载 JSON,而是等你点击搜索按钮时才去加载,帮大家省点流量。
  • 防抖处理:输入时不会每敲一个字都去搜索,而是稍微停顿一下再触发,避免频繁计算。
  • PJAX 适配:因为博客用了 PJAX 做无刷新跳转,一开始遇到个坑,点击搜索结果页面会白屏或者刷新。后来发现需要在渲染结果后,手动调用一下 window.pjax.refresh(),让 PJAX 重新接管这些新生成的链接。
// 简单的搜索逻辑
const results = window.searchIndex.filter(item => {
    // 简单的关键词匹配
    return item.title.includes(query) || item.summary.includes(query);
});
displayResults(results);

4. 那个“随笔”变搜索框的交互

这个交互其实主要是 CSS 在控制。

默认是一个普通的 <h2> 标题,点击后通过 JS 隐藏标题,显示输入框。为了过渡自然一点,加了一些简单的 CSS 动画。

/* 默认隐藏提示 */
.search-hint {
    opacity: 0;
    transition: all 0.3s ease;
}

/* 鼠标放上去显示 */
.section-header.normal-mode:hover .search-hint {
    opacity: 1;
    transform: translateX(0);
}

为了照顾移动端用户,我在 CSS 里加了媒体查询,手机上直接显示“点击搜索”的提示,不然手机上没有 hover 状态,可能会不知道这里可以点。

遇到的坑

折腾过程中最大的坑还是 PJAX

一开始写好的时候,搜索功能本身没问题,但是点搜索结果跳转的时候,要么页面刷新,要么音乐播放器断了。查了半天文档,才发现是因为动态插入的 HTML(搜索结果列表),PJAX 默认是监听不到的。

解决办法就是在插入 HTML 后,手动通知一下 PJAX:

if (window.pjax) window.pjax.refresh(searchResults);

另外,为了体验好一点,我还加了个逻辑:点击搜索结果后,自动关闭搜索框,不然跳转完搜索框还挡在那里,确实有点傻。

总结

虽然只是个小功能,但前前后后也调了好久,特别是细节上的打磨。不过看到最后丝滑的搜索体验,感觉还是挺值得的。

如果你也在用 Hugo,不想接复杂的第三方搜索,不妨试试这个方案,轻量、简单,完全够用了。

代码就不全贴了,核心逻辑都在上面,有兴趣的朋友可以自己折腾一下。如果有更好的实现方式,也欢迎留言交流哈!