前言
之前我们创建博客后已经在 hugo.toml 配置文件中开启了文章评论功能
[params]
comments = true但这只是打开了评论开关,并没有真正实现评论功能,因为 hugo 搭建的是竞态网站,并不提供数据库存储服务,因此需要我们自己实现一套评论系统。
好消息是目前已经有成熟稳定的方案,我们只需要简单几步和少量代码将其接入到自己的博客即可使用。这里我们介绍的是基于 github Discussion 的 Giscus App。
一、评论系统:Giscus(完整生产方案)
选择 Giscus 的理由:基于 GitHub Discussions,免费稳定、无广告、无需数据库、支持 Markdown/代码高亮/表情反应,且与 GitHub 账号体系打通(对技术博客读者非常自然)。
步骤 1:GitHub 端准备
-
准备仓库:新建(或沿用现有)一个公开 GitHub 仓库,用于存放评论数据。仓库必须是
public,否则 Giscus 无法读取。 -
开启 Discussions:进入仓库 →
Settings→General→Features→ 勾选 Discussions。 -
安装 Giscus App:访问 github.com/apps/giscus → 点击 Install → 选择 Only select repositories → 勾选你的仓库 → 保存。遵循最小权限原则,不要授权给所有仓库。
-
获取配置参数:访问 giscus.app(有中文界面),填写你的仓库名,选择:
- 页面 ↔️ Discussion 映射:
pathname(最稳定,换域名不丢评论) - Discussion 分类:
Announcements(该分类下的讨论不会出现在仓库首页动态,更干净) - 主题:先随便选一个,后面 Hugo 端会配置自动切换
- 语言:
zh-CN
页面底部会生成一段
<script>,记录下其中的data-repo、data-repo-id、data-category、data-category-id四个值。 - 页面 ↔️ Discussion 映射:
步骤 2:安全加固(防止脚本被盗用)
在 Hugo 站点仓库的根目录(与 hugo.toml 同级,不是 static/ 目录)创建 giscus.json:
{
"origins": ["https://example.org"],
"defaultCommentOrder": "newest"
}这会让 Giscus 只在你自己的域名下加载,防止他人盗用你的评论组件。
步骤 3:Hugo 配置
在 hugo.toml 的 [params] 块内新增:
[params.giscus]
repo = "yourname/yourrepo" # 例:dake/blog-comments
repoId = "R_xxxxxxxxxx" # 从 giscus.app 复制
category = "Announcements"
categoryId = "DIC_xxxxxxxxxx" # 从 giscus.app 复制
mapping = "pathname"
strict = "0" # 0=宽松匹配(推荐),1=严格标题匹配
reactionsEnabled = "1" # 启用表情反应
emitMetadata = "0" # 不发送元数据
inputPosition = "bottom" # 评论框在底部
lightTheme = "light"
darkTheme = "dark"
lang = "zh-CN"注意:
repoId和categoryId必须以字符串形式保留(带引号),因为它们是字母数字混合 ID。
步骤 4:创建评论模板
创建文件 layouts/partials/comments.html,内容如下(完整代码,含 PaperMod 暗黑/亮色主题自动同步):
{{- if and .Site.Params.giscus .Site.Params.giscus.repo -}}
<div class="comments-wrapper" style="margin-top: 3rem;">
<div class="comments-header" style="text-align: center; margin-bottom: 1.5rem;">
<h3 style="font-size: 1.25em; font-weight: 700; margin-bottom: 0.25rem;">评论</h3>
<p style="font-size: 0.9rem; color: var(--secondary);">使用 GitHub 账号登录后参与讨论</p>
</div>
<div id="giscus-container"></div>
</div>
<script>
const getStoredTheme = () => {
const pref = localStorage.getItem("pref-theme");
if (pref === "dark") return "{{ .Site.Params.giscus.darkTheme | default "dark" }}";
if (pref === "light") return "{{ .Site.Params.giscus.lightTheme | default "light" }}";
// 用户从未手动切换过,跟随系统偏好
return "preferred_color_scheme";
};
const setGiscusTheme = () => {
const sendMessage = (message) => {
const iframe = document.querySelector('iframe.giscus-frame');
if (iframe) {
iframe.contentWindow.postMessage({ giscus: message }, 'https://giscus.app');
}
};
sendMessage({ setConfig: { theme: getStoredTheme() } });
};
document.addEventListener("DOMContentLoaded", () => {
// 创建 giscus 挂载容器
const giscusDiv = document.createElement("div");
giscusDiv.className = "giscus";
document.querySelector("#giscus-container").appendChild(giscusDiv);
// 动态创建 script,确保 theme 初始值正确
const giscusAttributes = {
"src": "https://giscus.app/client.js",
"data-repo": "{{ .Site.Params.giscus.repo }}",
"data-repo-id": "{{ .Site.Params.giscus.repoId }}",
"data-category": "{{ .Site.Params.giscus.category }}",
"data-category-id": "{{ .Site.Params.giscus.categoryId }}",
"data-mapping": "{{ .Site.Params.giscus.mapping | default "pathname" }}",
"data-strict": "{{ .Site.Params.giscus.strict | default "0" }}",
"data-reactions-enabled": "{{ .Site.Params.giscus.reactionsEnabled | default "1" }}",
"data-emit-metadata": "{{ .Site.Params.giscus.emitMetadata | default "0" }}",
"data-input-position": "{{ .Site.Params.giscus.inputPosition | default "bottom" }}",
"data-theme": getStoredTheme(),
"data-lang": "{{ .Site.Params.giscus.lang | default "zh-CN" }}",
"data-loading": "lazy",
"crossorigin": "anonymous",
"async": "",
};
const giscusScript = document.createElement("script");
Object.entries(giscusAttributes).forEach(([key, value]) => {
giscusScript.setAttribute(key, value);
});
document.querySelector("#giscus-container").appendChild(giscusScript);
// 监听 PaperMod 主题切换按钮(桌面端 + 移动端浮动按钮)
const themeSwitcher = document.querySelector("#theme-toggle");
if (themeSwitcher) {
themeSwitcher.addEventListener("click", setGiscusTheme);
}
const themeFloatSwitcher = document.querySelector("#theme-toggle-float");
if (themeFloatSwitcher) {
themeFloatSwitcher.addEventListener("click", setGiscusTheme);
}
});
</script>
{{- else -}}
{{- warnf "comments.html: Giscus 参数未配置完整,跳过渲染" -}}
{{- end -}}步骤 5:可选 CSS 美化
如果你希望评论区上方的标题更美观,创建 assets/css/extended/comments.css:
.comments-wrapper {
padding-top: 1rem;
border-top: 1px solid var(--border);
}
.comments-header h3 {
color: var(--primary);
}
.comments-header p {
color: var(--secondary);
margin: 0;
}
assets/css/extended/是 PaperMod 约定自动加载自定义 CSS 的目录,无需额外配置。
步骤 6:验证
- 本地重新运行
hugo server -D -F --disableFastRender,打开任意文章页,滚动到底部。 - 如果看到"使用 GitHub 账号登录后参与讨论"和 Giscus 加载框,说明成功。
- 点击 PaperMod 顶部的 🌙/☀️ 主题切换按钮,Giscus 评论区应同步切换暗黑/亮色。
评论
使用 GitHub 账号登录后参与讨论