本文介绍如何在 Astro 博客中集成 Giscus 评论系统,采用原生 JavaScript 方案,无需额外依赖。
前提条件
- GitHub 仓库必须是公开的
- 已安装 Giscus GitHub App
- 已为仓库开启 Discussions 功能
获取配置参数
- 访问 Giscus 配置页面
- 输入你的仓库信息
- 选择讨论分类映射方式(推荐使用
pathname
) - 选择主题(我们会在代码中动态切换主题)
- 记录生成的配置参数,主要是:
- repo
- repo-id
- category
- category-id
创建评论组件
创建文件 src/components/Comments.astro
:
---
---
<section class="mx-auto mt-12">
<div id="giscus-container">
<script
is:inline
src="https://giscus.app/client.js"
data-repo="你的用户名/仓库名"
data-repo-id="你的仓库ID"
data-category="Blog Post Comments"
data-category-id="你的分类ID"
data-mapping="pathname"
data-strict="0"
data-reactions-enabled="1"
data-emit-metadata="0"
data-input-position="top"
data-theme="noborder_light"
data-lang="zh-CN"
crossorigin="anonymous"
async
></script>
</div>
</section>
<script is:inline>
function updateGiscusTheme() {
const theme = document.documentElement.getAttribute("data-theme") === "dark"
? "dark_dimmed"
: "light";
const iframe = document.querySelector("iframe.giscus-frame");
if (iframe) {
iframe.contentWindow.postMessage(
{ giscus: { setConfig: { theme } } },
"https://giscus.app"
);
} else {
const giscusContainer = document.getElementById("giscus-container");
if (giscusContainer) {
const giscusScript = giscusContainer.querySelector("script");
if (giscusScript) {
giscusScript.setAttribute(
"data-theme",
theme === "dark" ? "noborder_dark" : "noborder_light"
);
}
}
}
}
// 初始化时更新主题
updateGiscusTheme();
// 监听主题变化
const observer = new MutationObserver(updateGiscusTheme);
observer.observe(document.documentElement, {
attributes: true,
attributeFilter: ["data-theme"],
});
// 页面加载完成时更新主题
window.addEventListener("load", updateGiscusTheme);
// 监听 iframe 加载
const bodyObserver = new MutationObserver(() => {
if (document.querySelector("iframe.giscus-frame")) {
updateGiscusTheme();
}
});
bodyObserver.observe(document.body, {
childList: true,
subtree: true,
});
</script>
主要配置说明:
data-mapping="pathname"
: 使用页面路径映射评论data-reactions-enabled="1"
: 启用表情反应data-input-position="top"
: 评论框在顶部data-lang="zh-CN"
: 使用中文界面data-theme="noborder_light"
: 默认使用无边框亮色主题
添加到文章布局
修改 src/layouts/PostDetails.astro
:
---
import Comments from "@/components/Comments.astro";
// ... 其他导入
---
<Layout {...layoutProps}>
<!-- ... 其他内容 ... -->
<hr class="my-6 border-dashed" />
<Comments />
<!-- ... 其他内容 ... -->
</Layout>
主题切换原理
- 使用
MutationObserver
监听data-theme
属性变化 - 当主题切换时,通过
postMessage
更新 Giscus iframe 的主题 - 使用
noborder_light
和noborder_dark
主题,保持整洁的外观
优点
- 不需要额外的依赖(如 React)
- 代码简洁,易于维护
- 性能好,加载快
- 完美支持明暗主题切换
- 配置集中在组件内,方便修改
常见问题
-
评论不显示
- 检查仓库是否公开
- 确认 Discussions 功能已开启
- 验证配置参数是否正确
-
主题不跟随切换
- 确保网站使用
data-theme
属性控制主题 - 检查
updateGiscusTheme
函数是否正确执行
- 确保网站使用
-
评论框位置不对
- 调整
data-input-position
参数 - 修改
section
的 margin 样式
- 调整
结语
这种实现方式不仅简单,而且性能好,推荐在 Astro 项目中使用。如果你需要更复杂的功能,也可以考虑使用 React 版本的实现。
参考资料
注意事项
-
script 标签的
is:inline
指令- 当 script 标签带有属性(如
src
)时,Astro 会自动将其视为内联脚本 - 建议显式添加
is:inline
指令,这样可以:- 避免构建时的警告提示
- 明确表示这是一个不需要处理的外部脚本
- 符合 Astro 的最佳实践
- 这不影响功能,只是代码风格的改进
- 当 script 标签带有属性(如
-
配置参数说明
data-repo
和data-repo-id
:你的 GitHub 仓库信息data-category
和data-category-id
:Giscus 讨论分类data-mapping
:使用 pathname 进行页面映射data-theme
:评论区主题样式data-lang
:界面语言设置