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

文章页随机推荐功能实现

AI 智能总结

需求背景

原有的文章底部展示区使用 Hugo 内置的 Related 方法,根据标签(权重 100)和分类(权重 80)计算文章之间的相关度,展示关联度最高的 6 篇文章。

这种方式的局限在于——如果读者正在阅读一篇技术文章,推荐的全是同类技术文章。虽然相关度高,但很容易让读者局限于单一分类,错失其他分类中的优质内容。

改进方案:改为全站随机推荐,每次刷新随机展示 6 篇完全不同的文章,打破分类壁垒,让内容发现更加多元化。

实现方案

核心修改

修改 layouts/_default/single.html 中只有一行关键代码:

修改前(基于相关度匹配):

1{{ $related := site.RegularPages.Related . | first 6 }}

修改后(全站随机抽取):

1{{ $randomPosts := shuffle (where site.RegularPages "Permalink" "!=" .Permalink) | first 6 }}

代码解析

函数/过滤作用
site.RegularPages获取全站所有常规文章
where ... "Permalink" "!=" .Permalink排除当前正在阅读的文章(不推荐自己)
shuffleHugo 内置函数,随机打乱切片顺序
first 6取前 6 篇作为推荐展示

shuffle 是 Hugo 0.84+ 版本内置的函数,无需额外配置,每次页面构建时执行一次随机排序。

标题和图标更新

为了让读者理解这是随机推荐而非精准匹配,同步更新了标题和图标:

  • 标题:相关文章猜你喜欢
  • 图标:fa-book-openfa-random
1<span class="related-icon"><i class="fas fa-random"></i></span>
2<h3 class="related-title">猜你喜欢</h3>

shuffle 的使用注意事项

构建时随机,非运行时随机

shuffle 在 Hugo 构建阶段执行一次。这意味着:

  • 每次重新构建部署后,每篇文章底部的推荐列表会变化
  • 但在同一部署周期内,刷新页面不会改变顺序(因为是纯静态 HTML)
  • 如果需要每次访问都变化,需要配合 JavaScript 随机或定期触发 CI/CD 重新构建

排除特殊页面

当前全站文章数量适中,shuffle 从全部文章中抽取。如果网站存在不想出现在推荐中的特殊页面(如"关于"、“友链"这些独立页面),它们本身就不在 RegularPages 中(RegularPages 只包含常规内容页面),因此不需要额外过滤。

RegularPages 自动排除以下类型:

  • _index.md 章节页
  • Type 为特殊类型的页面(取决于 Hugo 配置中的 mainSections

性能

shuffle 是 Go 标准库级别的随机排序,时间复杂度为 O(n)。即使数千篇文章,性能也完全可控。

其他随机推荐方案

方案一:按分类比例随机(均衡版)

如果想要每个分类都有展示机会,可以按分类抽样:

1{{ $all := where site.RegularPages "Permalink" "!=" .Permalink }}
2{{ range $all | shuffle | first 2 }}
3  ...
4{{ end }}

直接用 shuffle 是最简单公平的做法。

方案二:结合标签权重随机(混合版)

保留部分相关性,同时引入随机性:

1{{ $tagRelated := site.RegularPages.Related . | first 4 }}
2{{ $others := shuffle (where site.RegularPages "Permalink" "!=" .Permalink) | first 2 }}
3{{ $mixed := $tagRelated | append $others | uniq }}

这样 4 篇与当前文章有一定关联,2 篇完全随机,兼顾精准和探索。

方案三:排除最近看过的文章

配合前端 LocalStorage 记录读者近期浏览历史,前端层面二次过滤:

1const viewedUrls = JSON.parse(localStorage.getItem('viewedUrls') || '[]');
2// 隐藏最近浏览过的推荐卡片
3document.querySelectorAll('.related-card').forEach(card => {
4  if (viewedUrls.includes(card.href)) {
5    card.style.display = 'none';
6  }
7});

配置项清理

原有的 hugo.toml[related] 配置段已不再被页面模板使用(Related 方法不再被调用)。该配置段可以保留(不产生副作用),也可以删除以精简配置:

 1# 以下配置已经不再被页面模板使用,可保留或删除
 2[related]
 3  includeNewer = true
 4  threshold = 80
 5  toLower = true
 6  [[related.indices]]
 7    name = "tags"
 8    weight = 100
 9  [[related.indices]]
10    name = "categories"
11    weight = 80

效果对比

维度原方案(Related)新方案(Shuffle)
推荐逻辑基于标签和分类的相关度算法全站等概率随机
推荐范围同分类/同标签为主全部分类
重复性同一篇文章每次推荐相同每次构建后变化
内容发现窄,容易"信息茧房”广,打破分类壁垒
实现复杂度需配置 indices 和 weight一行代码
适用场景分类明确的技术文档站多元化内容博客

总结

Related 切换到 shuffle 只需要一行代码改动,但用户体验的改善是显著的:读者在阅读完一篇文章后,不再被同类内容包围,而是有机会发现博客中完全不同领域的文章。这对于内容分类丰富、题材多样的个人博客来说尤为重要。

13 / 16
版权声明

本文作者 Lumin

本文链接 https://www.zhengquan.xyz/biji/random-post-recommendation/

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

请作者喝杯咖啡 ☕

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

留言评论

期待你的想法

评论加载中