1799 字
9 分钟Add commentMore actions
Fuwari添加评论功能

示例#

---
title: Fuwari添加评论功能
published: 2025-02-22
description: "静态博客养成计划"
image: ""
tags: ["Fuwari", "教程"]
category: Guides
draft: false
comments: true
---

Waline 评论#

Waline 是一款简洁、安全的评论系统。优点:布置简单,功能强大。 官方地址: Waline官方

动手之前先去按照Waline官网教程创建一个账号,并部署好数据库与服务端

安装 Waline 依赖#

终端界面输入:

Terminal window
pnpm add -D @waline/client

如果报错缺少 @waline/apirecaptcha-v3

Terminal window
pnpm i -D @waline/api recaptcha-v3

添加 Waline 评论#

  • 通过在原有astro组件上修改
  • 添加新astro组件以在需要时调用

通过在原有astro组件上修改#

NOTE

该方式仅单独对文章启用 Waline 评论

  1. src/config.ts 中的 walineConfig 配置项里添入自己部署的 Waline 项目的域名。
export const walineConfig = {
//填入你的域名
serverURL: "",
login: "force",
};
  1. src/content/config.ts 中添加 comments 关键词:
schema: z.object({
title: z.string(),
published: z.date(),
updated: z.date().optional(),
draft: z.boolean().optional().default(false),
description: z.string().optional().default(""),
image: z.string().optional().default(""),
tags: z.array(z.string()).optional().default([]),
category: z.string().optional().default(""),
lang: z.string().optional().default(""),
comments: z.boolean().optional().default(false),
/* For internal use */
prevTitle: z.string().default(""),
prevSlug: z.string().default(""),
nextTitle: z.string().default(""),
nextSlug: z.string().default(""),
}),
  1. src\pages\posts\[...slug].astro 添加 Waline 组件:

修改导包:

import { licenseConfig, walineConfig } from "src/config";

将 Waline 嵌入页脚的两个 </div> 标签后:

如图: alt text

<!-- Waline -->
{entry.data.comments !== false && (
<div class="card-base z-10 px-6 md:px-9 pt-6 pb-4 relative w-full mb-4">
<div id="waline" />
<script type="module" is:inline define:vars={{ walineConfig }}>
import { init } from 'https://unpkg.com/@waline/client@v3/dist/waline.js';
function loadWaline() {
init({
el: '#waline',
serverURL: walineConfig.serverURL,
login: walineConfig.login,
path: location.pathname,
wordLimit: ["2", "1000"],
dark: '.dark',
});
}
loadWaline();
</script>
</div>
)}

src\layouts\Layout.astro 约 149 行 </head>标签前添加

<link rel="stylesheet" href="https://unpkg.com/@waline/client@v3/dist/waline.css" />
TIP

如若使用了我后面写到的优化后的waline组件,则 src\pages\posts\[...slug].astro 这样写(Layout.astro无需再添加css样式):

---
//在开头处导入组件
import Waline from "@components/Waline/Waline.astro";
---
<!-- Waline -->
{entry.data.comments !== false && <Waline client:visible/>}
  1. src/types/config.ts 声称 comments 类型:
export type BlogPostData = {
body: string;
title: string;
published: Date;
description: string;
tags: string[];
draft?: boolean;
image?: string;
category?: string;
prevTitle?: string;
prevSlug?: string;
nextTitle?: string;
nextSlug?: string;
comments?: boolean;
};

添加新astro组件以在需要时调用(TODO)#

  1. src\components 目录下创建 Waline.astro:

并添加内容:

Waline.astro
<!-- 引入Waline评论 -->
<link rel="stylesheet" href="https://unpkg.com/@waline/client@v3/dist/waline.css" />
<div id="waline"></div>
<script type="module">
import { init } from 'https://unpkg.com/@waline/client@v3/dist/waline.js';
// 监听主题变化
function initWaline() {
const isDark = document.documentElement.classList.contains('dark');
init({
el: '#waline',
serverURL: 'your serverURL',
dark: isDark ? 'html.dark' : false, // 关键配置
comment: true, // 评论数统计
reaction: [ // 反馈表情,使用默认的也可以
'https://gcore.jsdelivr.net/gh/norevi/waline-blobcatemojis@1.0/blobs/ablobcatheart.png',//比心
'https://gcore.jsdelivr.net/gh/norevi/waline-blobcatemojis@1.0/blobs/blobcatalt.png', //可爱
'https://gcore.jsdelivr.net/gh/norevi/waline-blobcatemojis@1.0/blobs/ablobcatwave.png',//打招呼
'https://gcore.jsdelivr.net/gh/norevi/waline-blobcatemojis@1.0/blobs/blobcatthink.png',//思考
'https://gcore.jsdelivr.net/gh/norevi/waline-blobcatemojis@1.0/blobs/ablobcatheartbroken.png',//心碎
'https://gcore.jsdelivr.net/gh/norevi/waline-blobcatemojis@1.0/blobs/blobcatgay.png',//难平
],
emoji: [
// 必须使用有效的CDN地址
'https://gcore.jsdelivr.net/gh/norevi/waline-blobcatemojis@1.0/blobs',
'https://cdn.jsdelivr.net/npm/@waline/emojis@1.3.0/qq',
],
});
}
// 初始化
initWaline();
// 监听主题切换(根据你的主题实现方式调整)
const observer = new MutationObserver(() => {
const container = document.getElementById('waline');
if (container && container.innerHTML) {
container.innerHTML = ''; // 清空重新初始化
initWaline();
}
});
observer.observe(document.documentElement, {
attributes: true,
attributeFilter: ['class']
});
</script>
TODO

并未采用异步策略,可能会增加相关性能开销,后续还要优化 已更新

这里暂时使用别人做的优化版astro组件

原主如果看到可以留言嗷

<!-- 1. 先静态显示阅读量/评论数的骨架屏 -->
<!-- 可选,不需要可以直接删掉下面的-->
<div id="waline-info">
<div style="display: flex; align-items: center;">
阅读量: <span class="waline-pageview-count" style="margin-left: 5px;">--</span>
</div>
<div style="display: flex; align-items: center;">
评论数:<span class="waline-comment-count" style="margin-left: 5px;">--</span>
</div>
</div>
<!-- 2. 评论容器(初始为空) -->
<div id="waline"></div>
<!-- 3. 异步加载逻辑 -->
<script is:inline>
(async () => {
const loadCSS = () => {
const link = document.createElement('link');
link.rel = 'stylesheet';
link.href = 'https://unpkg.com/@waline/client@v3/dist/waline.css';
document.head.appendChild(link);
};
const { init } = await import('https://unpkg.com/@waline/client@v3/dist/waline.js');
const initWaline = () => {
const isDark = document.documentElement.classList.contains('dark');
init({
el: '#waline',
serverURL: 'your serverURL',
dark: isDark ? 'html.dark' : false,
pageview: true,
comment: true,
emoji: [
'https://gcore.jsdelivr.net/gh/norevi/waline-blobcatemojis@1.0/blobs',
'https://cdn.jsdelivr.net/npm/@waline/emojis@1.3.0/qq',
],
});
};
// 并行加载资源
loadCSS();
initWaline();
new MutationObserver(() => {
const container = document.getElementById('waline');
if (container?.innerHTML) {
container.innerHTML = '';
initWaline();
}
}).observe(document.documentElement, {
attributes: true,
attributeFilter: ['class']
});
})();
</script>
<style>
#waline-info {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 10px;
}
#waline {
clear: both;
}
.waline-pageview-count::before,
.waline-comment-count::before {
content: '';
display: inline-block;
width: 1em;
height: 1em;
background: #eee;
animation: pulse 1.5s infinite;
vertical-align: middle;
margin-right: 0.3em;
}
@keyframes pulse {
0%, 100% { opacity: 0.5; }
50% { opacity: 1; }
}
</style>

推荐使用优化修改后的代码:

src/components/Waline.astro
---
import { walineConfig } from "src/config";
// 将 Waline 的配置项定义在这里,方便传入到客户端脚本
const walineOptions = {
serverURL: walineConfig.serverURL,
comment: true, // 评论数统计
emoji: [
// 必须使用有效的CDN地址
"https://gcore.jsdelivr.net/gh/norevi/waline-blobcatemojis@1.0/blobs",
"https://cdn.jsdelivr.net/npm/@waline/emojis@1.3.0/qq",
],
reaction: [
// 反馈表情,使用默认的也可以
"https://gcore.jsdelivr.net/gh/norevi/waline-blobcatemojis@1.0/blobs/ablobcatheart.png", //比心
"https://gcore.jsdelivr.net/gh/norevi/waline-blobcatemojis@1.0/blobs/blobcatalt.png", //可爱
"https://gcore.jsdelivr.net/gh/norevi/waline-blobcatemojis@1.0/blobs/ablobcatwave.png", //打招呼
"https://gcore.jsdelivr.net/gh/norevi/waline-blobcatemojis@1.0/blobs/blobcatthink.png", //思考
"https://gcore.jsdelivr.net/gh/norevi/waline-blobcatemojis@1.0/blobs/ablobcatheartbroken.png", //心碎
"https://gcore.jsdelivr.net/gh/norevi/waline-blobcatemojis@1.0/blobs/blobcatgay.png", //难平
],
// Waline v3 的关键配置:当 'html.dark' 类存在时,Waline 会自动切换到暗色模式
// 无需MutationObserver监听,Waline内部会处理
dark: "html.dark",
// 你可以在这里添加更多Waline配置,例如 pageview, locale, path等
// pageview: true,
// path: typeof window !== "undefined" ? window.location.pathname : "/", // 在SSR时处理window对象
// locale: {
// placeholder: '留下你的评论...'
// }
};
---
<!-- 引入 Waline 评论的 CSS,建议放在 head 中或者组件顶部 -->
<link
rel="stylesheet"
href="https://unpkg.com/@waline/client@v3/dist/waline.css"
/>
<!-- Waline 评论容器 -->
<div id="waline"></div>
<!--客户端脚本:
- 通过 `data-options` 属性将配置安全地传递给客户端脚本。
- 使用动态 import() 来真正懒加载 Waline 的 JS 库。
-->
<script
type="module" is:inline
id="waline-init-script"
data-options={JSON.stringify(walineOptions)}
>
// 获取脚本标签上的配置数据
const scriptTag = document.getElementById("waline-init-script");
const options = JSON.parse(scriptTag.dataset.options);
// 动态导入 Waline 客户端库
// 只有当组件进入视口时,才会下载 Waline 的 JS 文件
import("https://unpkg.com/@waline/client@v3/dist/waline.js")
.then(({ init }) => {
init({
el: "#waline", // Waline 挂载的元素ID
path: location.pathname,
...options, // 展开传入的配置项
});
console.log("Waline comments initialized successfully!");
})
.catch((err) => {
console.error("Failed to load Waline comments:", err);
});
</script>
<style>
/* 可以在这里添加一些针对Waline容器的样式,例如最小高度,加载提示等 */
#waline {
clear: both;
}
</style>
  1. 在相关astro界面合适的位置导入 Waline 然后调用即可:
Article.astro
---
import Waline from '@/components/Waline.astro';
---
<!-- 引入评论组件 -->
<Waline />
<!--TODO:如果要动态加载(在被观测到时加载)-->
<!--还有不少内容要修改,暂时别用-->
<Waline client:visible />
NOTE

博客以内容输出为主,尽可能都以内容优先,视情况动态加载 ;w;

Waline 相关组件属性#

管理员与管理面板#

首个注册的账号会是管理员,管理面板在 example.yourdomain.com/ui

Giscus 评论#

创建 giscus 仓库#

  1. 创建一个新的GitHub库用来存储博客的那些评论,请确保该仓库是 公开的 ,否则访客将无法正常查看 discussion
  2. 给你的这个repo仓库安装giscus app,否则访客将无法评论和回应。
  3. 确保 Discussions 功能已在你的仓库中启用

配置 giscus#

打开giscus 官方网站,进行配置:

  • 语言:选择你目前正在使用的语言
  • 仓库:填写你刚刚创建的仓库(格式为你的用户名/仓库名)
  • 页面 ↔️ discussion 映射关系(默认即可)
  • Discussion 分类(默认即可)
  • 特性(默认即可)
  • 主题(默认即可)

按照顺序配置好之后,下方会自动生成:

<!-- giscus评论 -->
<!-- 评论区域的间距根据实际情况修改 也可以删除 -->
<div style="margin-top: 20px;"></div>
<script src="https://giscus.app/client.js"
data-repo="[在此输入仓库]"
data-repo-id="[在此输入仓库 ID]"
data-category="[在此输入分类名]"
data-category-id="[在此输入分类 ID]"
data-mapping="pathname"
data-strict="0"
data-reactions-enabled="1"
data-emit-metadata="0"
data-input-position="bottom"
data-theme="preferred_color_scheme"
data-lang="zh-CN"
crossorigin="anonymous"
async>
</script>

使用 giscus#

  1. 修改对应的如about.astroposts.astroarchive.astro 等等

在页尾前添加即可

<!-- giscus评论 -->
</MainGridLayout>
  1. 创建giscus.astro组件 ,在需要时导入调用

方法同 waline ,照搬即可

Fuwari添加评论功能
https://p1ume.vercel.app/posts/fuwari/comment/
作者
p1ume
发布于
2025-02-22
许可协议
CC BY-NC-SA 4.0