5.主题魔改:创建“最新评论”独立页面

5.主题魔改:创建“最新评论”独立页面

重要前提:再次提醒,这是Twikoo方案
核心流程概览
  1. 创建“最新评论”页面文件:通过Hexo命令生成 /messages/ 页面。
  2. 粘贴“三合一”代码:这份教程将页面的HTML结构、CSS样式和JS逻辑全部集成在一个文件中,我们只需复制粘贴即可。
  3. 在代码中配置您的个人信息:修改JS代码,使其连接到您自己的Twikoo后端。

第一步:创建“最新评论”页面
  1. 执行创建页面命令

    • 在您Hexo博客的根目录下,打开终端,输入:
    1
    hexo new page messages
  2. 打开文件

    • 找到并打开新生成的 source/messages/index.md 文件。

第二步:粘贴“三合一”代码

这份教程采用了一种“All-in-One”的集成方式。请将您 source/messages/index.md 文件的全部内容,用下面提供的完整代码进行覆盖。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
---
title: 最新评论
aside: false
comments: false
---

<div class="author-content author-content-item single" style="background:url(https://lib.bsgun.cn/Hexo-static/img/essay-bg.avif) center /cover no-repeat!important">
<div class="card-content">
<div class="author-content-item-tips">速览</div>
<span class="author-content-item-title">最新评论</span>
<div class="content-bottom">
<div class="tips">快速预览本站最新评论</div>
</div>
<div class="banner-button-group">
<a class="banner-button" style="padding: 8px 12px;color: var(--anzhiyu-white);" onclick="pjax.loadUrl(&quot;/about&quot;)" data-pjax-state="">
<i class="anzhiyufont anzhiyu-icon-arrow-circle-right" style="font-size:22px;margin-right:.25rem"></i>
<span class="banner-button-text">关于本人</span>
</a>
</div>
</div>
</div>

<div id="comments-page">
<img src="https://lib.bsgun.cn/Hexo-static/img/loading.gif" alt="Loading...">
</div>

<style>
/* 全局样式 */
h1 {
display: none;
}
div#page {
background: none !important;
box-shadow: none;
padding: 0;
border: none;
}
/* 评论页面容器 */
#comments-page {
display: flex;
flex-wrap: wrap;
gap: 12px;
width: 100%;
margin-top: 1.5rem;
justify-content: center;
}
/* 评论卡片基础样式 */
.comment-card {
position: relative;
width: calc(100% / 4 - 9px);
border-radius: 12px;
border: 1px solid var(--anzhiyu-card-border);
padding: 14px;
overflow: hidden;
box-shadow: var(--anzhiyu-shadow-border);
animation: slide-in .6s .4s backwards;
background-color: var(--anzhiyu-card-bg);
transition: all .3s ease-in-out;
}
.comment-card:hover {
border: 1px solid var(--anzhiyu-main);
}
/* 评论信息区域 */
.comment-info {
padding-bottom: 5px;
border-bottom: 2px dashed var(--anzhiyu-theme-op);
}
.comment-information {
display: flex;
flex-direction: column;
}
.comment-user {
font-weight: bold;
}
.comment-time {
font-size: 12px;
color: var(--anzhiyu-secondtext);
}
/* 评论内容 */
.comment-content {
position: relative;
z-index: 3;
overflow: hidden;
padding-top: 5px;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
}
/* 头像样式 */
.avatar-wrapper {
position: absolute;
top: 50%;
right: 10px;
transform: translateY(-50%);
width: 100px;
height: 100px;
border-radius: 50%;
opacity: 0.4;
transition: all 0.3s ease-in-out;
filter: blur(3px);
background-size: cover;
background-position: center;
}
.comment-card:hover .avatar-wrapper {
transform: translateY(-50%) scale(1.1);
opacity: 0.6;
}
/* 响应式布局 */
@media (max-width: 1024px) {
.comment-card {
width: calc(100% / 2 - 6px);
}
}
@media (max-width: 768px) {
.comment-card {
width: 100%;
}
.banner-button-group {
display: none;
}
}
</style>
<script>
(() => {
const MessageComments = {
// --- 在这里进行您的个性化配置 ---
API_URL: 'https://twikoo.prorise666.site/', // 【必填】这里填入您的Twikoo服务器地址
ADMIN_EMAIL_MD5: 'ec3291d59a8d7d3675df8a0537fcbc979f0fa611c8df55841fb7f4fd162bd07a', // 【必填】这里填入您的邮箱md5值
PAGE_SIZE: 100, // 显示的评论数量
// --- 配置结束 ---

async fetchComments() {
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), 5000);
try {
const response = await fetch(this.API_URL, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
event: 'GET_RECENT_COMMENTS',
includeReply: true,
pageSize: this.PAGE_SIZE
}),
signal: controller.signal
});
const { data } = await response.json();
return data;
} catch (error) {
console.error('获取评论出错:', error);
return null;
} finally {
clearTimeout(timeoutId);
}
},
formatTimeAgo(timestamp) {
const diff = Math.floor((Date.now() - new Date(timestamp)) / 1000);
if (diff < 60) return '刚刚';
if (diff < 3600) return `${Math.floor(diff / 60)}分钟前`;
if (diff < 86400) return `${Math.floor(diff / 3600)}小时前`;
if (diff < 604800) return `${Math.floor(diff / 86400)}天前`;
return new Date(timestamp).toLocaleDateString('zh-CN', { month: 'numeric', day: 'numeric' }) + '日';
},
formatContent(content) {
if (!content) return '';
return content
.replace(/<pre><code>[\s\S]*?<\/code><\/pre>/g, '[代码块]')
.replace(/<code>([^<]{4,})<\/code>/g, '[代码]')
.replace(/<code>([^<]{1,3})<\/code>/g, '$1')
.replace(/<img[^>]*>/g, '[图片]')
.replace(/<a[^>]*?>[\s\S]*?<\/a>/g, '[链接]')
.replace(/<[^>]+>/g, '')
.replace(/&(gt|lt|amp|quot|#39|nbsp);/g, m => ({'>':'>', '<':'<', '&':'&', 'quot':'"', '#39':"'", 'nbsp':' '})[m.slice(1,-1)])
.replace(/\s+/g, ' ')
.trim();
},
generateCommentHTML(comment) {
const { created, comment: content, url, avatar, nick, mailMd5, id } = comment;
const timeAgo = this.formatTimeAgo(created);
const formattedContent = this.formatContent(content);
const adminBadge = mailMd5 === this.ADMIN_EMAIL_MD5 ? '<i class="fa fa-check-circle" style="color: #57bd6a; margin-left: 5px;"></i>' : '';
return `<div class="comment-card" onclick="pjax.loadUrl('${url}#${id}')" title="点击查看评论"><div class="avatar-wrapper" style="background-image: url('${avatar}');"></div><div class="comment-info"><div class="comment-information"><span class="comment-user">${nick} ${adminBadge}</span><span class="comment-time">${timeAgo}</span></div></div><div class="comment-content">${formattedContent}</div></div>`;
},
getErrorTemplate(message) {
return `<p style="text-align: center; color: #666;">${message}</p>`;
},
async init() {
const container = document.querySelector('#comments-page');
if (!container) return;
const comments = await this.fetchComments();
let content;
if (comments === null) {
content = this.getErrorTemplate('加载评论时出错,请稍后再试');
} else if (comments.length === 0) {
content = this.getErrorTemplate('没有找到相关评论');
} else {
content = comments.map(this.generateCommentHTML.bind(this)).join('');
}
container.innerHTML = content;
requestAnimationFrame(() => {
container.querySelectorAll('.comment-card').forEach(el => {
el.style.opacity = '1';
});
});
}
};
['DOMContentLoaded', 'pjax:success'].forEach(event =>
document.addEventListener(event, () => MessageComments.init())
);
})();
</script>

第三步:在代码中修改您的个人配置
  1. 在您刚刚粘贴的代码中,找到 <script> 标签内的 MessageComments 对象。
  2. 修改以下几个关键参数:
    • API_URL: 【必填】 将其值替换为您自己部署的 Twikoo 后端服务地址。
    • ADMIN_EMAIL_MD5: 【必填】 替换为您自己作为博主的邮箱的MD5值,用于在评论卡片上显示“博主”认证图标。您可以在线搜索“MD5生成器”来计算您邮箱的MD5值。
  3. 您还可以修改HTML结构中默认的背景图和加载动画的链接,换成您自己的图片。

最后一步:配置路由
1
2
3
4
5
# 预览相关菜单项
预览:
音乐馆: /music/?server=netease&id=3117791189 || anzhiyu-icon-music
相册集: /album/ || anzhiyu-icon-images
评论总览: /messages/ || fas fa-comments

请记住,这个页面只有在您拥有一个正常运行的Twikoo后端服务,并将正确的 API_URL 配置进去后,才能成功加载并显示评论。