本篇魔改教程只适用于 Twikoo评论 ,其他评论系统可自行修改适配。
并且内容会有涉及到最新评论页的部分js常量函数,请优先阅读:Butterfly的魔改教程:最新评论页

效果预览

在PC端文章右下角处即可查看评论弹窗

创建数据

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

  • [主题目录]/layout/includes/layout.pug文件中,新增以下内容。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
      main#content-inner.layout(class=hideAside)
if body
div!= body
else
block content
if theme.aside.enable && page.aside !== false
include widget/index.pug

+ if page.comments !== undefined && page.comments !== false && theme.comments.use
+ #comment-barrage

- const footerBg = theme.footer_img
- const footer_bg = footerBg ? footerBg === true ? bg_img : getBgPath(footerBg) : ''
footer#footer(style=footer_bg)
!=partial('includes/footer', {}, {cache: true})
  • 新建[主题目录]/source/css/_layout/barrage.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
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
#comment-barrage
position fixed
bottom 40px
right calc(10px + 48px)
display flex
flex-direction column
justify-content flex-end
align-items flex-end
transform translateY(190px)
transition .3s
z-index 1

+maxWidth768()
display none

&.show
transform translateY(0)

.comment-barrage-item
min-width 286px
max-width 286px
width fit-content
min-height 80px
max-height 150px
margin 4px
padding 8px 14px
background var(--icat-card-overlap)
border-radius 12px
color var(--icat-fontcolor)
animation barrageIn .6s cubic-bezier(0.42, 0, 0.3, 1.11)
transition .3s
display flex
flex-direction column
outline var(--icat-border-always)
position fixed
box-shadow var(--icat-shadow-border)
overflow hidden

&:hover
outline var(--icat-border-main)
box-shadow var(--icat-shadow-main)

&.out
opacity 0
animation barrageOut 0.6s cubic-bezier(0.42, 0, 0.3, 1.11)

pre, li, blockquote, br
display none

.barrageHead
height 30px
padding 0
line-height 30px
font-size 12px
border-bottom var(--icat-border-dashed)
display flex
justify-content space-between
align-items center
font-weight bold
padding-bottom 6px

.barrageAvatar
width 18px
height 18px
margin 0
margin-right 8px
border-radius 50%
background var(--icat-theme)

.barrageTime
margin-left 4px

.barrageClose
color var(--icat-secondtext)
cursor pointer
line-height 1
margin-left auto

&:hover
color var(--icat-theme)

.barrageContent
font-size 14px
font-weight normal
height calc(100% - 30px)
overflow hidden
width fit-content
max-height 48px

a
pointer-events:none
font-size 14px

&:-webkit-scrollbar
height 0
width 4px

&-button
display none

p
color var(--icat-fontcolor)
margin 8px 0 0
max-width calc(286px - 28px)
line-height 1.5
-webkit-line-clamp 2
display -webkit-box
-webkit-box-orient vertical
font-size 12px
font-weight bold
overflow hidden
text-overflow ellipsis
transition .3s

&:hover
color var(--icat-theme)

img
&:not(.tk-owo-emotion)
display none

&.tk-owo-emotion
width 16px
padding 0
margin 0
transform translateY(2px)

@keyframes barrageIn
0%
transform translateY(20px)
opacity 0

100%
transform translateY(0)
opacity 1

@keyframes barrageOut
0%
transform translateY(0)
opacity 1

100%
transform translateY(20px)
opacity 0
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
let commentData
+let commentInterval = null

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
},

···

+ barrage: async () => {
+ const tlol = btf.saveToLocal.get('comment-pop')
+ const barrage = document.getElementById('comment-barrage')
+ if (tlol === 'off' || !barrage) return
+
+ const ScrollBarrage = () => {
+ const scrollResidue = (window.scrollY + document.documentElement.clientHeight) >= (document.getElementById("post-comment") || document.getElementById("footer")).offsetTop
+ barrage.classList.toggle('show', !scrollResidue)
+ }
+ const BarrageBox = (data) => {
+ const time = changeTime(new Date(data.created).toISOString(), true)
+
+ let barrages = document.createElement('div')
+ barrages.className = 'comment-barrage-item'
+ barrages.innerHTML = `<div class="barrageHead"><img class="barrageAvatar" src="${data.avatar}" /><div class="barrageNick">${data.nick}</div><div class="barrageTime">${time}曾评论</div><a class="barrageClose" href="javascript:comment.closeBarrage(true)"><i class="MeuiCat icon-close-fill"></i></a></div><a class="barrageContent" href="javascript:void(0)" onclick="btf.scrollToDest(btf.getEleTop(document.getElementById('${data.id}')), 300)"><p>${data.commentText.trim()}</p></a>`
+
+ box.push(barrages)
+ barrage.append(barrages)
+ }
+ const removeBarrage = (e) => {
+ if (!e) return
+ e.className = 'comment-barrage-item out'
+ setTimeout(() => barrage.removeChild(e), 1000)
+ }
+
+ btf.addEventListenerPjax(window, 'scroll', ScrollBarrage, { passive: true })

+ let hoverBarrage = false, index = 0, box = []
+ const url = `"url": window.location.pathname`
+ const data = await comment.fetchData(url)
+ if (!data.length) return

+ barrage.addEventListener('mouseenter', () => hoverBarrage = true)
+ barrage.addEventListener('mouseleave', () => hoverBarrage = false)

+ clearInterval(commentInterval)
+ commentInterval = setInterval(() => {
+ if (box.length >= 1 && !hoverBarrage) removeBarrage(box.shift())
+ if (!hoverBarrage) {
+ BarrageBox(data[index])
+ index = (index + 1) % data.length
+ }
+ }, 5000)
+ },
+ closeBarrage: (state = false) => {
+ const removeBarrage = () => {
+ const $comment = document.querySelector('#comment-barrage')
+ $comment.className = 'out'
+ setTimeout(() => { $comment.innerHTML = '', $comment.className = 'show' }, 1000)
+ }
+
+ if (state) return clearInterval(commentInterval), removeBarrage()
+
+ const comments = btf.saveToLocal.get('comment-pop')
+ btf.saveToLocal.set('comment-pop', comments === 'off' ? 'on' : 'off', 2)
+ comments === 'off' ? comment.barrage() : (clearInterval(commentInterval), removeBarrage())
+ }
}
btf.addGlobalFn('pjaxComplete', comment.new(), 'comment')
+btf.addGlobalFn('pjaxComplete', comment.barrage(), 'barrage')

注意:如果你没有实现最新评论页功能,就需要新增整个comment函数,并将 {envId}{YOUR_TOKEN} 需要替换为对应值

旧版教程

更新历史

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