本篇魔改教程只适用于 Twikoo评论 ,其他评论系统可自行修改适配。

20241224更新中优化了很多东西,包括教程的上手难度都做出了很多的调整,小白也可以快速上手。

效果预览

创建数据

小节开始前,提醒事项。
对于初次魔改新手,建议先过一遍:魔改前置教程:添加自定义css和js文件

  • 创建[博客根目录]/source/comments/index.md文件。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
---
title: 最新评论
date: 2023-07-17 14:07:01
type: comments
top_img: false
aside: false
top_page: true
top_bg: https://img.meuicat.com/banner
top_item: 速览
top_title: 最新评论
top_tips: 快速预览本站最新评论
---

<!-- 页面内容 -->
  • 修改[主题目录]/layout/page.pug来使页面匹配。
1
2
3
4
5
6
7
      when 'shuoshuo'
include includes/page/shuoshuo.pug
+ when 'comments'
+ include includes/page/comments.pug
default
include includes/page/default-page.pug
+commentLoad
  • 新建[主题目录]/layout/includes/page/comments.pug页面,并新增以下内容。
1
2
3
#comments-page
.page-load
img(src="https://img.meuicat.com/blog/loading.svg" style="margin:auto")
  • 新建[主题目录]/source/css/_page/comment.styl样式文件,并新增以下内容。
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
#comments-page
display: flex
flex-wrap: wrap
gap: 12px

.comment-card
position: relative
width: calc(100% / 4 - 36px / 4)
border-radius: 12px
outline: var(--icat-border-always)
padding: 12px
overflow: hidden
box-shadow: var(--icat-shadow-border)
background: var(--icat-card-bg)
animation: slide-in .6s .4s backwards

+maxWidth768()
width: 100%

&:hover
.comment-more
opacity: 1

.comment-info
display: flex
align-items: center
padding-bottom: 12px
margin-bottom: 8px
border-bottom: var(--icat-border-dashed)
gap: 12px

img
width: 50px
height: 50px
object-fit: cover
border-radius: 50%
margin: 0 !important

.comment-information
display: flex
flex-direction: column
line-height: 1.5

.comment-user
display: flex
align-items: center
font-weight: bold
font-size: 15px

.comment-author:after
content: "\e00c"
font-family: "MeuiCat" !important
padding-left: 6px
font-size: 14px
color: var(--icat-theme)

.comment-time
color: var(--icat-secondtext);
font-size: 12px

.comment-content
margin: 8px 5px 0
overflow: hidden
text-overflow: ellipsis
display: -webkit-box
-webkit-box-orient: vertical
-webkit-line-clamp: 2
font-size: 14px
font-weight: 400
line-height: 1.7

.comment-more
position: absolute
inset: 0
height: 100%
width: 100%
z-index: 1
background: var(--icat-theme)
color: var(--icat-card-bg)
margin: 0
display: flex
padding: .5rem 1rem
opacity: 0
flex-direction: column
justify-content: space-between
transition: .3s ease-out

.comment-title
display: flex
align-items: center
justify-content: space-between

span
overflow: hidden
text-overflow: ellipsis
display: -webkit-box
-webkit-box-orient: vertical
-webkit-line-clamp: 1
font-weight: 700
cursor: pointer

i
margin-right: 4px

a
font-size: 14px
color: var(--icat-card-bg)
opacity: .6
margin-left: 4px
white-space: nowrap

#comment-tool
display: flex
flex-wrap: wrap
gap: 4px 8px

a
background: var(--icat-sparent)
color: var(--icat-card-bg)
border-radius: 8px
padding: 4px 8px
font-size: 14px
opacity: .6

a:hover
opacity 1 !important
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
let commentData

const comment = {
fetchData: async (option) => {
const res = await fetch('{envId}', {
method: "POST",
body: JSON.stringify({
"event": "GET_RECENT_COMMENTS",
"accessToken": "{YOUR_TOKEN}",
"includeReply": true,
"pageSize": -1,
...option
}),
headers: { 'Content-Type': 'application/json' }
}).then(res => res.json())

return res.data
},
new: async (type, exclude) => {
const comments = document.getElementById('comments-page')
if (!comments) return

const commentclick = () => {
document.querySelectorAll('#comment-tool a').forEach(e =>
e.addEventListener('click', comment.operate)
)
}
const [a, b, c] = [`<a href="javascript:void(0)" data-type="post" title="显示此文章所有评论">查看更多</a>`, `<a href="javascript:void(0)" data-type="visitor" title="显示该评论者的所有评论">查看Ta更多评论</a>`, `<a href="javascript:void(0)" data-type="all" title="查看本站最新评论">返回评论</a>`]

let data, tool, html = ''
if (!commentData) commentData = await comment.fetchData()
data = commentData
if (type) data = data.filter(item => item[type] === exclude), tool = type === 'mailMd5' ? a + c : b + c
else data = data.slice(0, 50), tool = a + b
if (!ArticleData) await toRandomPost(true)

data.forEach(item => {
const time = changeTime(item.created, true)
const title = Object.values(ArticleData).flatMap(data => data).find(article => article.link === item.url)?.title || '未知标题'

html += `<div class="comment-card"><div class="comment-info"><img src="${item.avatar}"><div class="comment-information"><span class="comment-user ${item.mailMd5 === '91afb88f9ce8126f2825f7ef9fd64ceb' ? 'comment-author' : ''}" data-mailmd5="${item.mailMd5}">${item.nick}</span><span class="comment-time">${time}</span></div></div><div class="comment-content">${item.commentText.trim()}</div><div class="comment-more"><div class="comment-title"><span class="comment-link" title="查看此文章" onclick="pjax.loadUrl('${item.url}')"><i class="iconfont icat-read"></i>${title}</span><a href="javascript:void(0)" onclick="pjax.loadUrl('${item.url}#${item.id}')">查看评论</a></div><div id="comment-tool">${tool}</div></div></div>`
})
comments.innerHTML = html
commentclick()
},
operate: (event) => {
const type = event.target.getAttribute('data-type')
const commentCard = event.target.closest('.comment-card')
if (type === 'visitor') comment.new('mailMd5', commentCard.querySelector('.comment-user').getAttribute('data-mailmd5'))
if (type === 'post') comment.new('url', commentCard.querySelector('.comment-link').getAttribute('onclick').split("'")[1])
if (type === 'all') comment.new()
}
}
btf.addGlobalFn('pjaxComplete', comment.new(), 'comment')

{envId}{YOUR_TOKEN} 需要替换为对应值

Token获取

  • 在你的站点里,随便打开一篇文章,登录你的后台。

  • 随后在开发人员工具 - 应用 - 本地存储空间 - 你的网址 - twikoo-access-token里面即可看查看到你的Token。

注意事项

如果你此前并未实现随机文章功能,则需要进行下面的操作。

  • 新增[主题目录]/scripts/helpers/articles_json.js文件,新增以下内容。
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
/**
* MeuiCat
* generate json - pages_posts_random
* modify by yife.Liang
*/

'use strict'

hexo.extend.generator.register('thePages', function(locals) {
const postData = locals.posts
.filter(post => post.random !== false)
.map(post => {
const date = new Date(post.date);
const formattedDate = date.toISOString().split('T')[0];
return {
title: post.title || "暂无标题",
time: formattedDate,
update: post.updated ? new Date(post.updated).toISOString().replace('T', ' ').split('.')[0] : formattedDate,
link: post.permalink.replace(/^(?:\/\/|[^/]+)*\//, '/'),
cover: post.cover || hexo.theme.config.default_top_img
}
})
.sort((a, b) => new Date(b.time) - new Date(a.time))

const exclude = ['.js', '.wechatOA', '.json'];
const pageData = locals.pages
.filter(page => {return page.random !== false && !exclude.some(ext => page.source.endsWith(ext));})
.map(page => {
const date = new Date(page.date);
const formattedDate = date.toISOString().split('T')[0];
return {
title: page.title || "暂无标题",
time: formattedDate,
link: page.permalink.replace(/^(?:\/\/|[^/]+)*\//, '/').replace(/\/index\.html$/, '/')
}
})

const jsonData = {
post: postData,
page: pageData
}

return {
path: 'articles.json',
data: JSON.stringify(jsonData)
}
})
  • 打开[博客根目录]/source/js/meuicat.js文件,新增以下内容。
1
2
3
4
5
let ArticleData

const toRandomPost = async () => {
if (!ArticleData) ArticleData = await fetch('/articles.json').then(res => res.json())
}

进阶适配

旧版教程

更新历史

  • 230821 更新:新增article的JSON文件原生api,再也不用手动新增结构数据啦~

  • 230720 更新:修复控制台无容器时报错

  • 230718 更新:修复个人卡片显示评论数量异常。新增作者标识,提升UI样式

  • 240628 更新:新增评论过滤匹配功能;调整、减少冗余UI样式以及JS优化

  • 240702 更新:热评弹窗优化、UI调整、教程地址更新

  • 241224 更新:教程更新、优化代码,修复已知问题