国庆节10月1日
--


为说说页面的每条动态适配独立评论区,实现自定义聊天室 UI、邮件通知导航到详情页等功能。
.webp)
博客的说说功能上线一段时间了,但之前只有留言板有评论区,说说页面的评论功能一直没有完善。这次花了点时间,给每条说说都加上了独立的评论区,并且重新设计了评论 UI,让整体体验更接近现代聊天应用。
点击说说卡片右下角的评论按钮,会弹出一个评论弹窗。每条说说的评论是独立的,通过 Waline 的 path 参数区分。

评论弹窗采用了留言板的聊天室风格:

评论弹窗打开时会显示一个赛车加载动画,最低展示 2 秒后才显示评论内容。

当有人回复你的评论时,Waline 会发送邮件通知。邮件中的链接会直接跳转到对应的说说详情页(如 /moments/2026-07-25/),而不是动态列表页。

评论弹窗使用 Svelte 5 实现,核心是 CommentModal.svelte 组件:
1<script lang="ts">2 import { onMount } from "svelte";3 import CommentSidebarDesktop from "./CommentSidebarDesktop.svelte";4 import CommentSidebarMobile from "./CommentSidebarMobile.svelte";5
6 interface Props {7 serverURL: string;8 adminNicknames?: string[];9 }10
11 let { serverURL, adminNicknames = ["团子和蛋糕"] }: Props = $props();12
13 // 评论数据14 let comments: Comment[] = $state([]);15 let flatComments = $derived.by(() => {16 // 展平嵌套评论并按时间排序17 });18
19 // 弹窗状态20 let visible = $state(false);21 let phase = $state<"loader" | "comments">("loader");22
23 export function open(momentId: string, commentPath: string) {24 // 打开弹窗并加载评论25 }26</script>评论数据通过 Waline REST API 获取,而不是使用 Waline 的内置 UI:
1// 获取评论2const res = await fetch(`${serverURL}/api/comment?path=${encodeURIComponent(path)}&pageSize=100`);3const data = await res.json();4comments = data.data?.data || [];5
6// 发送评论7const body = {8 comment: `<p>${text.replace(/\n/g, "</p><p>")}</p>`,9 nick: nickText,10 mail: mailText,11 link: linkText,12 url: commentPath,13 ua: navigator.userAgent,14};15await fetch(`${serverURL}/api/comment`, {16 method: "POST",17 headers: { "Content-Type": "application/json" },18 body: JSON.stringify(body),19});为了支持邮件通知中的链接跳转,创建了说说详情页 src/pages/moments/[slug].astro:
1---2export async function getStaticPaths() {3 const moments = await getCollection("moments");4 return moments.map((moment) => ({5 params: { slug: moment.id },6 props: { moment },7 }));8}9---10
11<MomentCard moment={moment} detail={true} />
评论弹窗在桌面端和移动端有不同的布局:
通过 CSS Grid 和媒体查询实现响应式布局:
1/* 桌面端:两列布局 */2.chat-workspace {3 display: grid;4 grid-template-columns: 1fr 11rem;5}6
7/* 移动端:单列布局 */8@media (max-width: 640px) {9 .chat-workspace { grid-template-columns: 1fr; }10 .sidebar-desktop { display: none; }11 .sidebar-mobile { display: block; }12}
评论气泡参考了留言板的设计,使用 CSS 自定义属性适配深色/浅色主题:
1.msg-bubble {2 background: var(--guestbook-bubble);3 color: var(--guestbook-bubble-text);4 border-radius: var(--radius-medium);5 padding: var(--space-3) var(--space-4);6}7
8/* 站长消息 */9.msg.is-admin .msg-bubble {10 background: var(--guestbook-admin-bubble);11 color: var(--guestbook-admin-text);12}回复其他评论时,引用内容以边框样式显示在气泡内部:
1.msg-quote {2 border-left: 3px solid currentColor;3 padding: var(--space-2);4 opacity: 0.78;5 border-radius: var(--radius-small);6}
使用了一个赛车动画作为加载指示器,动画颜色跟随主题:
1.loader > span {2 background: var(--deep-text);3}4
5.base span {6 border-right: 100px solid var(--deep-text);7}这次升级让说说页面的评论体验更加完整:
后续还计划添加评论点赞、表情包等功能,让互动更加丰富。
如果你喜欢,那么欢迎来到我的世界!
了解更多暂未播放



"所有的相遇都是久别重逢。"—— 未知


