Hexo:为你的评论添加一个热评弹幕
文章摘要
Efu GPT
此内容根据文章生成,并经过人工审核,仅用于文章内容的解释与总结
投诉前言
在处理主题的热评功能时,偶然的一个想法,能否将热评代码提出来单独做成一个方法,只需要传递一个数组进去就能完美。
经过优化,已经适配双评论系统。
分享
实现代码
function initializeCommentBarrage(array) {
if (array === []) return;
let existingBarrage = window.currentBarrage;
if (existingBarrage) {
existingBarrage.destroy();
}
let barrage = class {
constructor() {
this.config = {
barrageTimer: [],
barrageList: [],
barrageIndex: 0,
dom: document.querySelector(".comment-barrage"),
maxBarrage: 1,
barrageTime: 5000
};
this.hoverOnCommentBarrage = false;
this.init();
}
filterAndFlatten(comments) {
return comments.flatMap(comment => comment.replies ? [comment, ...this.filterAndFlatten(comment.replies)] : [comment]);
}
sanitizeContent(content) {
return content.replace(/(<([^>]+)>)/ig, '').trim();
}
createBarrageItem(comment) {
const content = this.sanitizeContent(comment.content);
if (!content) return false;
const element = document.createElement("div");
element.className = "comment-barrage-item";
element.innerHTML = `<div class="barrageHead"><a class="barrageTitle" href="javascript:sco.scrollTo('post-comment')">弹幕</a><div class="barrageNick">${comment.nick}</div><img class="barrageAvatar" src="https://cravatar.cn/avatar/${comment.mailMd5}"/><a class="comment-barrage-close" href="javascript:sco.switchCommentBarrage();"><i class="solitude st-close-fill"></i></a></div><a class="barrageContent" href="${comment.id ? `javascript:sco.scrollTo(\'${comment.id}\')` : 'javascript:sco.scrollTo(\'post-comment\')'}">${content}</a>`;
this.config.dom.appendChild(element);
this.config.barrageTimer.push(element);
return true;
}
removeBarrageItem(element) {
element.classList.add("out");
setTimeout(() => this.config.dom.removeChild(element), 1000);
}
manageBarrage() {
if (this.config.barrageList.length && !this.hoverOnCommentBarrage) {
if (!this.createBarrageItem(this.config.barrageList[this.config.barrageIndex])) {
this.config.barrageIndex = (this.config.barrageIndex + 1) % this.config.barrageList.length;
return this.manageBarrage();
}
this.config.barrageIndex = (this.config.barrageIndex + 1) % this.config.barrageList.length;
}
if (this.config.barrageTimer.length > Math.min(this.config.maxBarrage, this.config.barrageList.length) && !this.hoverOnCommentBarrage) {
this.removeBarrageItem(this.config.barrageTimer.shift());
}
}
async initBarrage() {
this.config.dom.style.display = "flex"
this.config.barrageList = this.filterAndFlatten(array);
this.config.dom.innerHTML = "";
clearInterval(this.commentInterval);
this.commentInterval = setInterval(() => this.manageBarrage(), this.config.barrageTime);
}
async init() {
await this.initBarrage();
this.config.dom.addEventListener('mouseover', () => this.hoverOnCommentBarrage = true);
this.config.dom.addEventListener('mouseout', () => this.hoverOnCommentBarrage = false);
}
destroy() {
clearInterval(this.commentInterval);
this.config.dom.removeEventListener('mouseover', () => this.hoverOnCommentBarrage = true)
this.config.dom.removeEventListener('mouseout', () => this.hoverOnCommentBarrage = false)
this.config.dom.innerHTML = ""
}
}
window.currentBarrage = new barrage();
}
此方法会保持常开,如需要切换请自行添加Cookie
。
此方法中的跳转方法是sco.scrollTo('post-comment')
,请自行更改或自行设计。以下是 scrollTo 方法代码
function scrollTo(elementId) {
const targetElement = document.getElementById(elementId);
if (targetElement) {
const targetPosition = targetElement.getBoundingClientRect().top + window.pageYOffset - 80;
const startPosition = window.pageYOffset;
const distanceToScroll = targetPosition - startPosition;
let animationStartTime = null;
window.requestAnimationFrame((function smoothScroll(currentTime) {
animationStartTime = animationStartTime || currentTime;
const elapsedTime = currentTime - animationStartTime;
const progressRatio = Math.min(elapsedTime / 0, 1);
const easing = progressRatio < .5 ? 2 * progressRatio * progressRatio : (4 - 2 * progressRatio) * progressRatio - 1;
window.scrollTo(0, startPosition + distanceToScroll * easing);
elapsedTime < 600 && window.requestAnimationFrame(smoothScroll);
}));
}
}
div.comment-barrage
或
<div class="comment-barrage"></div>
样式代码
:root {
--efu-white: #fff;
--efu-white-op: rgba(255, 255, 255, 0.2);
--efu-black: #000;
--efu-black-op: rgba(0, 0, 0, 0.2);
--efu-none: rgba(0, 0, 0, 0);
--efu-gray: #999;
--efu-gray-op: rgba(153, 153, 153, 0.169);
--efu-cyan: #00bcd4;
--efu-cyan-op: rgba(0, 188, 212, 0.169);
--efu-vip: #e5a80d;
--efu-speed: #57bd6a;
--efu-main: var(--efu-theme);
--efu-main-op: var(--efu-theme-op);
--efu-main-op-deep: var(--efu-theme-op-deep);
--efu-main-op-light: var(--efu-theme-op-light);
--efu-main-none: var(--efu-theme-none);
--efu-shadow-theme: 0 8px 12px -3px var(--efu-theme-op);
--efu-shadow-blackdeep: 0 2px 16px -3px rgba(0, 0, 0, 0.15);
--efu-shadow-main: 0 8px 12px -3px var(--efu-main-op);
--efu-shadow-blue: 0 8px 12px -3px rgba(40, 109, 234, 0.2);
--efu-shadow-white: 0 8px 12px -3px rgba(255, 255, 255, 0.2);
--efu-shadow-black: 0 0 12px 4px rgba(0, 0, 0, 0.05);
--efu-shadow-yellow: 0px 38px 77px -26px rgba(255, 201, 62, 0.12);
--efu-shadow-red: 0 8px 12px -3px rgba(238, 125, 121, 0.212);
--efu-shadow-green: 0 8px 12px -3px rgba(135, 238, 121, 0.212);
--efu-logo-color: linear-gradient(215deg, #4584ff 0%, #cf0db9 100%);
--efu-snackbar-time: 5s;
--global-font-size: 14px;
--global-bg: #fff;
--hr-border: #97bcfb;
--hr-before-color: #6ea2f9;
--search-bg: #f6f8fa;
--search-input-color: #4c4948;
--search-result-title: #4c4948;
--preloader-bg: #37474f;
--preloader-color: #fff;
--tab-border-color: #f0f0f0;
--tab-botton-bg: #f0f0f0;
--tab-botton-color: #1f2d3d;
--tab-button-hover-bg: #dcdcdc;
--tab-button-active-bg: #fff;
--sidebar-bg: #f6f8fa;
--btn-hover-color: #ff7242;
--btn-color: #fff;
--btn-bg: #307af6;
--text-bg-hover: #307af6;
--light-grey: #eee;
--text-highlight-color: #1f2d3d;
--blockquote-color: #6a737d;
--blockquote-bg: rgba(73, 177, 245, 0.1);
--reward-pop: #f5f5f5;
--toc-link-color: #666261;
--card-box-shadow: 0 3px 8px 6px rgba(7, 17, 27, 0.06);
--card-hover-box-shadow: 0 3px 8px 6px rgba(7, 17, 27, 0.15);
--offset: 0px;
--hlscrollbar-bg: #121212;
}
[data-theme=dark] {
--efu-theme: #5bc167;
--efu-theme-op: rgba(91, 193, 103, 0.137);
--efu-theme-op-deep: rgba(91, 193, 103, 0.867);
--efu-theme-none: '#5BC16700';
--efu-blue: #0084ff;
--efu-red: #ff3842;
--efu-pink: #d44040;
--efu-green: #3e9f50;
--efu-purple: #7a60d2;
--efu-yellow: #ffc93e;
--efu-yellow-op: rgba(255, 201, 62, 0.188);
--efu-orange: #ff953e;
--efu-fontcolor: #f7f7fa;
--efu-background: #18171d;
--efu-reverse: #fff;
--efu-maskbg: rgba(0, 0, 0, 0.6);
--efu-maskbgdeep: rgba(0, 0, 0, 0.85);
--efu-hovertext: #0a84ff;
--efu-ahoverbg: #fff;
--efu-lighttext: var(--efu-theme);
--efu-secondtext: #a1a2b8;
--efu-scrollbar: rgba(200, 200, 223, 0.4);
--efu-card-btn-bg: #30343f;
--efu-post-blockquote-bg: #000;
--efu-post-tabs-bg: #121212;
--efu-secondbg: #30343f;
--efu-shadow-nav: 0 5px 20px 0px rgba(28, 28, 28, 0.4);
--efu-card-bg: #1b1c20;
--efu-card-bg-op: var(--efu-white-op);
--efu-card-bg-none: rgba(29, 27, 38, 0);
--efu-shadow-lightblack: 0 5px 12px -5px rgba(102, 68, 68, 0);
--efu-shadow-light2black: 0 5px 12px -5px rgba(102, 68, 68, 0);
--efu-card-border: #3d3d3f;
--efu-shadow-border: 0 8px 16px -4px rgba(0, 0, 0, 0.314);
--style-border: 1px solid var(--efu-card-border);
--style-border-always: 1px solid var(--efu-card-border);
--style-border-hover: 1px solid var(--efu-theme);
--style-border-hover-always: 1px solid var(--efu-theme);
--style-border-dashed: 1px dashed var(--efu-theme-op);
--style-border-forever: 2px solid var(--efu-lighttext);
--efu-hl-bg: #1c1e1e;
--efu-hltools-bg: #454a50;
}
[data-theme=light] {
--efu-theme: #0e83cd;
--efu-theme-op: rgba(14, 131, 205, 0.137);
--efu-theme-op-deep: rgba(14, 131, 205, 0.867);
--efu-theme-op-light: rgba(66, 89, 239, 0.051);
--efu-theme-none: '#0E83CD00';
--efu-blue: #425aef;
--efu-red: #f04a63;
--efu-pink: #ff7c7c;
--efu-green: #57bd6a;
--efu-yellow: #c28b00;
--efu-yellow-op: rgba(217, 156, 0, 0.102);
--efu-orange: #e38100;
--efu-purple: #7a60d2;
--efu-fontcolor: #363636;
--efu-background: #f7f9fe;
--efu-reverse: #000;
--efu-maskbg: rgba(255, 255, 255, 0.6);
--efu-maskbgdeep: rgba(255, 255, 255, 0.85);
--efu-hovertext: var(--efu-main);
--efu-ahoverbg: #f7f7fa;
--efu-lighttext: var(--efu-main);
--efu-secondtext: rgba(60, 60, 67, 0.8);
--efu-scrollbar: rgba(60, 60, 67, 0.4);
--efu-card-btn-bg: #edf0f7;
--efu-post-blockquote-bg: #fafcff;
--efu-post-tabs-bg: #f2f5f8;
--efu-secondbg: #f7f7f9;
--efu-shadow-nav: 0 5px 12px -5px rgba(102, 68, 68, 0.05);
--efu-card-bg: #fff;
--efu-card-bg-op: var(--efu-black-op);
--efu-card-bg-none: rgba(255, 255, 255, 0);
--efu-shadow-lightblack: 0 5px 12px -5px rgba(102, 68, 68, 0);
--efu-shadow-light2black: 0 5px 12px -5px rgba(102, 68, 68, 0);
--efu-card-border: #e3e8f7;
--efu-shadow-border: 0 8px 16px -4px rgba(44, 45, 48, 0.047);
--style-border: 1px solid var(--efu-card-border);
--style-border-always: 1px solid var(--efu-card-border);
--style-border-hover: 1px solid var(--efu-main);
--style-border-hover-always: 1px solid var(--efu-main);
--style-border-dashed: 1px dashed var(--efu-theme-op);
--style-border-forever: 2px solid var(--efu-main);
--efu-navbg: var(--efu-theme-op);
--efu-hl-bg: #fff;
--efu-hltools-bg: #e7e7e7;
}
.comment-barrage {
position: fixed;
bottom: 0;
right: 20px;
padding: 0 0 20px 10px;
display: flex;
flex-direction: column;
justify-content: flex-end;
z-index: 999;
transition: all 0.3s ease 0s;
user-select: none;
}
@media screen and (max-width: 768px) {
.comment-barrage {
display: none !important;
}
}
.comment-barrage .comment-barrage-item {
min-width: 300px;
max-width: 300px;
width: fit-content;
min-height: 80px;
max-height: 150px;
margin: 4px;
padding: 8px 14px;
background: var(--efu-maskbgdeep);
border-radius: 8px;
color: var(--efu-fontcolor);
animation: 0.6s cubic-bezier(0.42, 0, 0.3, 1.11) 0s 1 normal none running barrageIn;
transition: all 0.3s ease 0s;
display: flex;
flex-direction: column;
border: var(--style-border);
backdrop-filter: saturate(180%) blur(20px);
box-shadow: var(--efu-shadow-border);
overflow: hidden;
}
.comment-barrage .comment-barrage-item:hover {
border: var(--style-border-hover);
box-shadow: var(--efu-shadow-main);
}
.comment-barrage .comment-barrage-item.out {
opacity: 0;
animation: 0.6s cubic-bezier(0.42, 0, 0.3, 1.11) 0s 1 normal none running barrageOut;
}
.comment-barrage .comment-barrage-item.hovered {
opacity: 0;
}
.comment-barrage .comment-barrage-item .comment-barrage-close {
color: var(--efu-secondtext);
cursor: pointer;
line-height: 1;
margin: 4px;
}
.comment-barrage .comment-barrage-item .comment-barrage-close:hover {
color: var(--efu-main);
}
.comment-barrage .comment-barrage-item .comment-barrage-close .solitude {
color: var(--efu-fontcolor);
font-size: 18px;
}
.comment-barrage .comment-barrage-item .barrageHead {
height: 30px;
padding: 0px 0px 6px;
line-height: 30px;
font-size: 12px;
border-bottom: var(--style-border);
display: flex;
justify-content: space-between;
align-items: center;
font-weight: 700;
}
.comment-barrage .comment-barrage-item .barrageHead .barrageTitle {
color: var(--efu-card-bg);
margin-right: 8px;
background: var(--efu-fontcolor);
line-height: 1;
padding: 4px;
border-radius: 4px;
white-space: nowrap;
}
.comment-barrage .comment-barrage-item .barrageHead .barrageTitle:hover {
background: var(--efu-main);
color: var(--efu-white);
}
.comment-barrage .comment-barrage-item .barrageAvatar {
width: 16px;
height: 16px;
margin: 0px 8px 0px auto;
border-radius: 50%;
background: var(--efu-secondbg);
}
.comment-barrage .comment-barrage-item .barrageContent {
height: calc(100% - 30px);
overflow: hidden;
width: fit-content;
max-height: 48px;
font-size: 14px !important;
font-weight: 400 !important;
}
.comment-barrage .comment-barrage-item .barrageContent h1, .comment-barrage .comment-barrage-item .barrageContent h2, .comment-barrage .comment-barrage-item .barrageContent h3, .comment-barrage .comment-barrage-item .barrageContent h4 {
font-size: 14px !important;
font-weight: 400 !important;
margin: 8px 0px !important;
}
.comment-barrage .comment-barrage-item .barrageContent a {
pointer-events: none;
font-size: 14px !important;
}
.comment-barrage .comment-barrage-item .barrageContent p {
margin: 8px 0;
line-height: 1.3;
overflow: hidden;
text-overflow: ellipsis;
-webkit-line-clamp: 2;
display: -webkit-box;
-webkit-box-orient: vertical;
font-size: 14px;
max-width: 270px;
}
.comment-barrage .comment-barrage-item .barrageContent p img:not(.tk-owo-emotion), .comment-barrage .comment-barrage-item .barrageContent p display none, .comment-barrage .comment-barrage-item .barrageContent p img.tk-owo-emotion {
width: 16px;
padding: 0;
margin: 0;
transform: translateY(2px);
}
.comment-barrage .comment-barrage-item .barrageContent::-webkit-scrollbar {
height: 0;
width: 4px;
}
.comment-barrage .comment-barrage-item .barrageContent::-webkit-scrollbar-button {
display: none;
}
传入数据
[
{
nick: 'Efu',
content: '这是我的评论',
mailMd5: '这是我的邮箱MD5',
id: '这是此条评论的ID(填写后执行跳转)'
}
]
各类评论获取当前评论的方法
- Twikoo
async function barrageTwikoo() {
await fetch("twikoo envid", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({
event: "COMMENT_GET",
accessToken: "你的 Twikoo accessToken",
url: window.location.pathname
})
}).then(async res => {
if (!res.ok) throw new Error("HTTP error! status: " + res.status)
const data = await res.json();
}).catch(error => console.error("An error occurred while fetching comments: ", error))
}
展示
- 感谢您的赞赏。
赞赏名单
因为有你们的支持,我才体会到写文章的价值。
本文是原创文章,采用CC BY-NC-SA 4.0协议,完整转载请注明来自Ever Fu
评论 ()