Merge pull request #329 from chengzhongxue/main

留言板页面弹窗优化
This commit is contained in:
困困鱼 2023-07-27 00:19:34 +08:00 committed by GitHub
commit 4044ea363a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 500 additions and 312 deletions

View File

@ -1766,7 +1766,33 @@ spec:
- group: envelope_comment
label: 留言板
formSchema:
- $formkit: radio
label: 弹幕
name: enable_danmu
value: true
options:
- label: 启用
value: true
- label: 禁用
value: false
- $formkit: number
name: maxBarrage
value: 20
label: 弹幕数页数
placeholder: 请输入弹幕数页数
- $formkit: radio
label: 信笺
name: enable_envelope_comment
key: enable_envelope_comment
id: enable_envelope_comment
value: true
options:
- label: 启用
value: true
- label: 禁用
value: false
- $formkit: textarea
if: $get(enable_envelope_comment).value
name: title
label: 标题
placeholder: 请输入内容
@ -1774,6 +1800,7 @@ spec:
help: 支持 HTML 语法
- $formkit: group
name: custom_pic
if: $get(enable_envelope_comment).value
label: 信笺图片
value:
cover:
@ -1803,6 +1830,7 @@ spec:
value: "https://npm.elemecdn.com/hexo-butterfly-envelope/lib/after.png"
- $formkit: repeater
name: messageList
if: $get(enable_envelope_comment).value
label: 正文
value:
- content: "有什么想问的?"
@ -1817,12 +1845,14 @@ spec:
value: "有什么想问的?"
- $formkit: text
name: bottom
if: $get(enable_envelope_comment).value
label: 底部文本
placeholder: 请输入内容
value: 自动书记人偶竭诚为您服务!
help: 仅支持单行文本
- $formkit: number
name: height
if: $get(enable_envelope_comment).value
label: 高度
placeholder: 请输入内容
help: 信封划出的高度

View File

@ -257,5 +257,89 @@ let halo = {
};
Prism.hooks.add("complete", r)
}
},
addScript: (e,t,n)=>{
if (document.getElementById(e))
return n ? n() : void 0;
let a = document.createElement("script");
a.src = t,
a.id = e,
n && (a.onload = n),
document.head.appendChild(a)
},
danmu: (url,token,maxBarrage)=>{
const e = new EasyDanmaku({
el: "#danmu",
line: 10,
speed: 20,
hover: !0,
loop: !0
});
let t = saveToLocal.get("danmu");
if (t)
e.batchSend(t, !0);
else {
let n = [];
function a(e) {
return e = (e = (e = (e = (e = e.replace(/<\/*br>|[\s\uFEFF\xA0]+/g, "")).replace(/<img.*?>/g, "[图片]")).replace(/<a.*?>.*?<\/a>/g, "[链接]")).replace(/<pre.*?>.*?<\/pre>/g, "[代码块]")).replace(/<.*?>/g, "")
}
fetch(url, {
method: "POST",
body: JSON.stringify({
event: "GET_RECENT_COMMENTS",
accessToken: token,
includeReply: !1,
pageSize: maxBarrage
}),
headers: {
"Content-Type": "application/json"
}
}).then((e=>e.json())).then((({data: t})=>{
t.forEach((e=>{
null == e.avatar && (e.avatar = "https://cravatar.cn/avatar/d615d5793929e8c7d70eab5f00f7f5f1?d=mp"),
n.push({
avatar: e.avatar,
content: e.nick + "" + a(e.comment),
href: e.url + '#' + e.id
})
}
)),
e.batchSend(n, !0),
saveToLocal.set("danmu", n, .02)
}
))
}
document.getElementById("danmuBtn").innerHTML = "<button class=\"hideBtn\" onclick=\"document.getElementById('danmu').classList.remove('hidedanmu')\">显示弹幕</button> <button class=\"hideBtn\" onclick=\"document.getElementById('danmu').classList.add('hidedanmu')\">隐藏弹幕</button>"
},
//关闭留言板评论弹幕
closeCommentBarrage: function () {
let commentBarrage = document.querySelector('.comment-barrage');
if (commentBarrage) {
if ($(".comment-barrage").is(":visible")) {
$(".comment-barrage").hide();
$(".menu-commentBarrage-text").text("显示热评");
document.querySelector("#consoleCommentBarrage").classList.remove("on");
localStorage.setItem('commentBarrageSwitch', 'false');
}
}
},
//打开评论弹幕
openCommentBarrage: function () {
let commentBarrage = document.querySelector('.comment-barrage');
if (commentBarrage) {
if ($(".comment-barrage").is(":hidden")) {
$(".comment-barrage").show();
$(".menu-commentBarrage-text").text("关闭热评");
document.querySelector("#consoleCommentBarrage").classList.add("on");
localStorage.removeItem('commentBarrageSwitch');
btf.snackbarShow("✨ 已开启评论弹幕", false, 2000)
}
}
},
}

View File

@ -0,0 +1,140 @@
class EasyDanmaku {
constructor(t) {
this.container = this.checkParams(t), this.wrapperStyle = t.wrapperStyle || null, this.line = t.line || 10, this.speed = t.speed || 5, this.runtime = t.runtime || 10, this.colourful = t.colourful || !1, this.loop = t.loop || !1, this.hover = t.hover || !1, this.coefficient = t.coefficient || 1.38, this.originIndex = 0, this.originList = null, this.offsetValue = this.container.offsetHeight / this.line, this.vipIndex = 0, this.overflowArr = [], this.clearIng = !1, this.cleartimer = null, this.init(), this.handleEvents(t)
}
handleEvents(t) {
this.onComplete = t.onComplete || null, this.onHover = t.onHover || null
}
init() {
this.runstatus = 1, this.aisle = [], this.container.style.overflow = "hidden", this.hover && this.handleMouseHover(), "relative" !== Utils.getStyle(this.container, "position") && "fixed" !== Utils.getStyle(this.container, "position") && (this.container.style.position = "relative");
for (let t = 0; t < this.line; t++) this.aisle.push({
normalRow: !0,
vipRow: !0
})
}
checkParams(t) {
if (!document.querySelector(t.el)) throw `Could not find the ${t.el} element`;
if (t.wrapperStyle && "string" != typeof t.wrapperStyle) throw "The type accepted by the wrapperStyle parameter is string";
if (t.line && "number" != typeof t.line) throw "The type accepted by the line parameter is number";
if (t.speed && "number" != typeof t.speed) throw "The type accepted by the speed parameter is number";
if (t.colourful && "boolean" != typeof t.colourful) throw "The type accepted by the colourful parameter is boolean";
if (t.runtime && "number" != typeof t.runtime) throw "The type accepted by the runtime parameter is number";
if (t.loop && "boolean" != typeof t.loop) throw "The type accepted by the loop parameter is boolean";
if (t.coefficient && "number" != typeof t.coefficient) throw "The type accepted by the coefficient parameter is number";
if (t.hover && "boolean" != typeof t.hover) throw "The type accepted by the hover parameter is boolean";
if (t.onComplete && "function" != typeof t.onComplete) throw "The type accepted by the onComplete parameter is function";
if (t.onHover && "function" != typeof t.onHover) throw "The type accepted by the onHover parameter is function";
return document.querySelector(t.el)
}
send(t, e = null, i = null) {
if (0 == this.runstatus) return void this.overflowArr.push({
content: t,
normalClass: e
});
if (t.length < 1) return;
let n = document.createElement("div"),
r = 0,
s = this.speed,
o = null,
l = 0;
n.innerHTML = t, n.style.display = "inline-block", n.classList.add("default-style"), (e || this.wrapperStyle) && n.classList.add(e || this.wrapperStyle),
function a() {
if (r = Math.round(Math.random() * (this.line - 1)), this.aisle[r].normalRow) {
this.aisle[r].normalRow = !1, this.container.appendChild(n), s += n.offsetWidth / n.parentNode.offsetWidth * 2, n.style.cssText = `\n text-align:center;\n min-width:130px;\n will-change: transform;\n position:absolute;\n right: -${n.offsetWidth+130}px;\n transition: transform ${s}s linear;\n transform: translateX(-${n.parentNode.offsetWidth+n.offsetWidth+130}px);\n top: ${r*this.offsetValue}px;\n line-height:${this.offsetValue}px;\n color:${this.colourful?"#"+("00000"+(16777216*Math.random()<<0).toString(16)).substr(-6):void 0}\n `;
let t = (n.parentNode.offsetWidth + n.offsetWidth) / s / 60;
o = setInterval((() => {
l += t, l > n.offsetWidth * this.coefficient && (this.aisle[r].normalRow = !0, clearInterval(o))
}), 16.66), setTimeout((() => {
1 != n.getAttribute("relieveDel") && (i && i({
runtime: s,
target: n,
width: n.offsetWidth
}), n.remove())
}), 1e3 * s)
} else {
this.aisle.some((t => !0 === t.normalRow)) ? a.call(this) : (() => {
this.overflowArr.push({
content: t,
normalClass: e
}), this.clearIng || this.clearOverflowDanmakuArray()
})()
}
}.call(this)
}
batchSend(t, e = !1, i = null) {
let n = this.runtime || 1.23 * t.length;
this.originList = t, this.hasAvatar = e, this.normalClass = i;
let r = setInterval((() => {
this.originIndex > t.length - 1 ? (clearInterval(r), this.originIndex = 0, this.onComplete && this.onComplete(), this.loop && this.batchSend(this.originList, e, i)) : (e ? this.send(`<img src=${t[this.originIndex].avatar}>\n <a href=${t[this.originIndex].href} target='_blank'> <p>${t[this.originIndex].content}</p> </a>\n `, i || this.wrapperStyle) : this.send(t[this.originIndex], i || this.wrapperStyle), this.originIndex++)
}), n / t.length * 1e3)
}
centeredSend(t, e, i = 3e3, n = null) {
let r = document.createElement("div"),
s = 0;
r.innerHTML = t, (e || this.wrapperStyle) && r.classList.add(e || this.wrapperStyle),
function t() {
if (this.aisle[s].vipRow) this.container.appendChild(r), r.style.cssText = `\n position:absolute;\n left:50%;\n transform:translateX(-50%);\n top: ${s*this.offsetValue}px;\n `, this.aisle[s].vipRow = !1, setTimeout((() => {
n && n({
duration: i,
target: r,
width: r.offsetWidth
}), r.remove(), this.aisle[s].vipRow = !0
}), i);
else {
if (s++, s > this.line - 1) return;
t.call(this)
}
}.call(this)
}
play() {
const t = this.container.children;
for (let e = 0; e < t.length; e++) this.controlDanmakurunStatus(t[e], 1);
this.runstatus = 1, 0 !== this.overflowArr.length && this.clearOverflowDanmakuArray()
}
pause() {
const t = this.container.children;
for (let e = 0; e < t.length; e++) this.controlDanmakurunStatus(t[e], 0);
this.runstatus = 0
}
controlDanmakurunStatus(t, e) {
const i = 0,
n = /-(\S*),/;
if (e === 1) {
clearTimeout(t.timer);
const e = Utils.getStyle(t, "transform").match(n)[1];
t.style.transition = `transform ${this.speed}s linear`, t.style.transform = `translateX(-${t.parentNode.offsetWidth+parseInt(e)+t.offsetWidth+130}px)`, t.timer = setTimeout((() => {
t.remove()
}), 1e3 * this.speed)
} else if (e === i) {
clearTimeout(t.timer);
const e = Utils.getStyle(t, "transform").match(n)[1];
t.style.transition = "transform 0s linear", t.style.transform = `translateX(-${e}px)`, t.setAttribute("relieveDel", 1)
}
}
handleMouseHover() {
Utils.eventDelegation(this.container, "default-style", "mouseover", (t => {
t.style["z-index"] = 1e3, this.controlDanmakurunStatus(t, 0), this.onHover && this.onHover(t)
})), Utils.eventDelegation(this.container, "default-style", "mouseout", (t => {
t.style.zIndex = 1, 1 == this.runstatus && this.controlDanmakurunStatus(t, 1)
}))
}
clearOverflowDanmakuArray() {
clearInterval(this.cleartimer), this.clearIng = !0;
let t = 0;
this.cleartimer = setInterval((() => {
0 === this.overflowArr.length ? (t++, t > 20 && (clearInterval(this.cleartimer), this.clearIng = !1)) : (this.send(this.overflowArr[0].content, this.overflowArr[0].normalClass || this.wrapperStyle), this.overflowArr.shift())
}), 500)
}
}
class Utils {
static getStyle(t, e) {
return window.getComputedStyle(t, null)[e]
}
static eventDelegation(t, e, i, n) {
t.addEventListener(i, (t => {
try {
t.target.className.includes(e) && n(t.target)
} catch (t) {}
}))
}
}

View File

@ -7,347 +7,272 @@
<div class="page" id="body-wrap">
<!-- 头部导航栏 -->
<header class="not-top-img" id="page-header">
<nav th:replace="~{modules/nav :: nav(title = null)}"></nav>
</header>
<main class="layout hide-aside" id="content-inner">
<div id="page">
<th:block th:if="${not #strings.isEmpty(theme.config.envelope_comment.title)}">
<h1>[[${theme.config.envelope_comment.title}]]</h1>
</th:block>
<style>
@media screen and (max-width: 600px) {
#afterimg,
#beforeimg {
display: none !important
}
}
<th:block th:if="${theme.config.envelope_comment.enable_envelope_comment}">
<th:block th:if="${not #strings.isEmpty(theme.config.envelope_comment.title)}"
th:utext="${theme.config.envelope_comment.title}">
</th:block>
<style>
@media screen and (max-width: 600px) {
@media screen and (min-width: 600px) {
#article-container img {
margin: 0 auto 0
#afterimg,
#beforeimg {
display: none !important
}
}
#form-wrap {
overflow: hidden;
height: 447px;
position: relative;
top: 0;
transition: all 1s ease-in-out .3s;
z-index: 0
@media screen and (min-width: 600px) {
#article-container img {
margin: 0 auto 0
}
#form-wrap {
overflow: hidden;
height: 447px;
position: relative;
top: 0;
transition: all 1s ease-in-out .3s;
z-index: 0
}
#form-wrap:hover {
height: [[${theme.config.envelope_comment.height}]]px;
top: -200px
}
#beforeimg {
position: absolute;
bottom: 126px;
left: 0;
background-repeat: no-repeat;
width: 530px;
height: 317px;
z-index: -100;
pointer-events: none
}
#afterimg {
position: absolute;
bottom: -2px;
left: 0;
background-repeat: no-repeat;
width: 530px;
height: 259px;
z-index: 100;
pointer-events: none
}
#envelope {
position: relative;
overflow: visible;
width: 500px;
margin: 0 auto;
transition: all 1s ease-in-out .3s;
padding-top: 200px
}
#maincontent {
width: 530px;
margin: 20px auto 0
}
.formmain {
background: #fff;
width: 95%;
max-width: 800px;
margin: auto auto;
border-radius: 5px;
border: 1px solid;
overflow: hidden;
-webkit-box-shadow: 0 0 20px 0 #000;
box-shadow: 0 0 20px 0 #000
}
}
#form-wrap:hover {
height: [[${theme.config.envelope_comment.height}]]px;
top: -200px
[data-theme=dark] .formmain {
background: #323232
}
#beforeimg {
position: absolute;
bottom: 126px;
left: 0;
background-repeat: no-repeat;
width: 530px;
height: 317px;
z-index: -100;
pointer-events: none
[data-theme=dark] .comments {
background: #5a5a5a !important
}
</style>
#afterimg {
position: absolute;
bottom: -2px;
left: 0;
background-repeat: no-repeat;
width: 530px;
height: 259px;
z-index: 100;
pointer-events: none
}
#envelope {
position: relative;
overflow: visible;
width: 500px;
margin: 0 auto;
transition: all 1s ease-in-out .3s;
padding-top: 200px
}
<div id="article-container">
<div id="maincontent">
<div id="form-wrap">
<img class="no-lightbox entered loaded" id="beforeimg"
th:src="@{${theme.config.envelope_comment.custom_pic.beforeimg}}">
<div id="envelope">
<form>
<div class="formmain" style="pointer-events:none">
<img class="headerimg no-lightbox entered loaded"
th:src="@{${theme.config.envelope_comment.custom_pic.cover}}"
style="width:100%;overflow:hidden;pointer-events:none">
<div class="comments-main">
<h3 class="title3"
style="text-decoration:none;color:var(--heo-theme);text-align:center">
来自[[${site.title}]]的留言:</h3>
<div class="comments"
style="text-align:center;border-bottom:#ddd 1px solid;border-left:#ddd 1px solid;padding-bottom:20px;background-color:#eee;margin:15px 0;padding-left:20px;padding-right:20px;border-top:#ddd 1px solid;border-right:#ddd 1px solid;padding-top:20px"
th:with="message = ${theme.config.envelope_comment.messageList}">
#maincontent {
width: 530px;
margin: 20px auto 0
}
.formmain {
background: #fff;
width: 95%;
max-width: 800px;
margin: auto auto;
border-radius: 5px;
border: 1px solid;
overflow: hidden;
-webkit-box-shadow: 0 0 20px 0 #000;
box-shadow: 0 0 20px 0 #000
}
}
[data-theme=dark] .formmain {
background: #323232
}
[data-theme=dark] .comments {
background: #5a5a5a !important
}
#danmu {
width: 100%;
height: calc(100% - 60px);
position: fixed;
left: 0;
top: 60px;
z-index: 1;
pointer-events: none;
}
/* 评论弹幕 */
.barrage {
position: fixed;
right: -500px;
display: inline-block;
width: fit-content;
z-index: 999
}
.barrage_box {
display: flex;
background-color: rgba(0, 0, 0, .5);
padding-right: 8px;
height: 40px;
border-radius: 25px;
}
.barrage_box .portrait {
display: inline-block;
margin-top: 4px;
margin-left: 4px;
width: 32px;
height: 32px;
border-radius: 50%;
overflow: hidden;
}
.barrage_box .portrait img {
width: 100%;
height: 100%;
}
.barrage_box div.p a {
display: inline-block;
white-space: nowrap;
max-width: 25rem;
margin-right: 2px;
font-size: 14px;
line-height: 40px;
margin-left: 10px;
overflow: hidden;
text-overflow: ellipsis;
text-decoration: none;
}
.barrage_box div.p a:hover {
text-decoration: underline;
}
.hidedanmu {
opacity: 0;
}
.hidedanmu * {
pointer-events: none !important;
}
div#danmuBtn {
display: flex;
justify-content: center;
margin: 20px;
}
div#danmuBtn button {
background: var(--heo-theme);
color: white;
padding: 8px 20px;
margin: 0 20px;
border-radius: 100px;
}
.barrage {
pointer-events: all;
cursor: pointer;
display: flex;
justify-content: center;
align-items: center;
font-size: 16px;
border-radius: 100px;
background-color: rgba(0, 0, 0, 0.5);
padding: 6px 16px 6px 6px;
color: #eee;
}
.barrage:hover {
background-color: rgba(0, 0, 0, 0.7);
transition: .3s
}
.barrage img {
pointer-events: none;
height: 30px;
width: 30px;
margin: 0 5px 0 0 !important;
border-radius: 50%;
}
.barrage p {
line-height: 1;
pointer-events: none;
margin: 0 !important;
max-width: 300px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
</style>
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/gh/yaseng/jquery.barrager.js/dist/js/jquery.barrager.min.js"></script>
<div id="article-container">
<div id="maincontent">
<div id="form-wrap">
<img class="no-lightbox entered loaded" id="beforeimg"
th:src="@{${theme.config.envelope_comment.custom_pic.beforeimg}}">
<div id="envelope">
<form>
<div class="formmain" style="pointer-events:none">
<img class="headerimg no-lightbox entered loaded"
th:src="@{${theme.config.envelope_comment.custom_pic.cover}}"
style="width:100%;overflow:hidden;pointer-events:none">
<div class="comments-main">
<h3 class="title3"
style="text-decoration:none;color:var(--heo-theme);text-align:center">
来自[[${site.title}]]的留言:</h3>
<div class="comments"
style="text-align:center;border-bottom:#ddd 1px solid;border-left:#ddd 1px solid;padding-bottom:20px;background-color:#eee;margin:15px 0;padding-left:20px;padding-right:20px;border-top:#ddd 1px solid;border-right:#ddd 1px solid;padding-top:20px"
th:with="message = ${theme.config.envelope_comment.messageList}">
<div th:each="data : ${message}">[[${data.content}]]</div>
<div th:each="data : ${message}">[[${data.content}]]</div>
</div>
<div class="bottomcontent" style="text-align:center;margin-top:40px">
<img class="bottomimg no-lightbox entered loaded"
th:src="@{${theme.config.envelope_comment.custom_pic.line}}"
style="width:100%;margin:5px auto 5px auto;display:block;pointer-events:none">
</div>
<p class="bottomhr" style="font-size:12px;text-align:center;color:#999">
[[${theme.config.envelope_comment.bottom}]]</p>
</div>
<div class="bottomcontent" style="text-align:center;margin-top:40px">
<img class="bottomimg no-lightbox entered loaded"
th:src="@{${theme.config.envelope_comment.custom_pic.line}}"
style="width:100%;margin:5px auto 5px auto;display:block;pointer-events:none">
</div>
<p class="bottomhr" style="font-size:12px;text-align:center;color:#999">
[[${theme.config.envelope_comment.bottom}]]</p>
</div>
</div>
</form>
</form>
</div>
<img id="afterimg" class="no-lightbox entered loaded"
th:src="@{${theme.config.envelope_comment.custom_pic.afterimg}}">
</div>
<img id="afterimg" class="no-lightbox entered loaded"
th:src="@{${theme.config.envelope_comment.custom_pic.afterimg}}">
</div>
</div>
</th:block>
<div class="flink" id="article-container">
<th:block th:utext="${singlePage.content.content}"></th:block>
</div>
<div id="loading"></div>
<div id="danmu"></div>
<div id="danmuBtn">
<button class="hideBtn"
onclick="document.getElementById('danmu').classList.remove('hidedanmu')">显示弹幕
</button>
<button class="hideBtn"
onclick="document.getElementById('danmu').classList.add('hidedanmu')">隐藏弹幕
</button>
</div>
<script>
let ls = []
let Num = 0;
// 以下注释为twikoo api的返回格式
// 返回 Array包含最新评论的
// * id: 评论 ID
// * url: 评论地址
// * nick: 昵称
// * mailMd5: 邮箱的 MD5 值,可用于展示头像
// * link: 网址
// * comment: HTML 格式的评论内容
// * commentText: 纯文本格式的评论内容
// * created: 评论时间,格式为毫秒级时间戳
// * avatar: 头像地址0.2.9 新增)
// * relativeTime: 相对评论时间,如 “1 小时前”0.2.9 新增)
// 返回示例: [ // 从新到旧顺序
// { id: '', url: '', nick: '', mailMd5: '', link: '', comment: '', commentText: '', created: 0 },
// { id: '', url: '', nick: '', mailMd5: '', link: '', comment: '', commentText: '', created: 0 },
// { id: '', url: '', nick: '', mailMd5: '', link: '', comment: '', commentText: '', created: 0 }
// ]
addEventListener("load",
() => {
// 手机端显示效果不好,所以直接不让其显示
if (1 && document.body.clientWidth > 768) {
// 加载动画,将 /themes/theme-hao/assets/images/load/rotating-ball-o.svg 换成你的加载图片即可
document.getElementById('loading').innerHTML = '<a href="/themes/theme-hao/assets/images/load/rotating-ball-o.svg" data-fancybox="gallery" data-caption="弹幕加载中..." data-thumb="/themes/theme-hao/assets/images/load/rotating-ball-o.svg" style="position: fixed;bottom: 100px;left: 4%;"><img src="/themes/theme-hao/assets/images/load/rotating-ball-o.svg" data-lazy-src="/themes/theme-hao/assets/images/load/rotating-ball-o.svg" alt="弹幕加载中..." data-ll-status="loaded" class="entered loaded"></a>';
let barrageTime = ''
// 使用twikoo 自带api请求全站数据
twikoo.getRecentComments({
envId: "[(${theme.config.comments.twikoos.envId})]", // 环境 ID
// region: 'ap-guangzhou', // 环境地域,默认为 ap-shanghai如果您的环境地域不是上海需传此参数
pageSize: 50, // 获取多少条默认10最大100
includeReply: false // 是否包括最新回复默认false
}).then((data) => {
data.forEach(i => {
if (i.avatar == undefined) i.avatar = 'https://cravatar.cn/avatar/d615d5793929e8c7d70eab5f00f7f5f1?d=mp'
ls.push({
img: i.avatar, //图片
info: i.nick + '' + formatDanmaku(i.comment), //文字
href: i.url, //链接
close: false, //显示关闭按钮
speed: 15, //延迟,单位秒,默认6
// bottom: 70, //距离底部高度,单位px,默认随机
color: '#fff', //颜色,默认白色
old_ie_color: '#000000', //ie低版兼容色,不能与网页背景相同,默认黑色
})
});
setTimeout(() => {
document.getElementById('loading').innerHTML = '';
}, 2000);
setInterval(() => {
if (Num >= ls.length) Num = 0
$('#danmu').barrager(ls[Num]);
Num++;
}, 1000); // 弹幕间隔时长
}).catch(function (err) {
console.error(err);
});
} else {
document.getElementById('loading').innerHTML = '<div class="note danger flat"><p>已关闭弹幕功能,请在电脑上查看。</p></div>' // 如果是手机则提醒
document.getElementById('danmuBtn').innerHTML = ''
}
})
<th:block th:if="${theme.config.comments.twikooEnable &&
#strings.equals(theme.config.comments.use, 'Twikoo') &&
theme.config.envelope_comment.enable_danmu }">
<div id="danmuBtn">
<button class="hideBtn"
onclick="document.getElementById('danmu').classList.remove('hidedanmu')">显示弹幕</button>
<button class="hideBtn"
onclick="document.getElementById('danmu').classList.add('hidedanmu')">隐藏弹幕</button>
</div>
<div id="danmu">
</div>
<style>
.default-style a {
color: #eee;
}
.default-style a:hover {
text-decoration: underline;
}
:root {
--hao-purple: #4976f5;
}
#article-container a:not(.headerlink, .fancybox) {
font-weight: 700;
color: #4c4948;
padding: 0 3px;
border-bottom: 2px var(--hao-purple) solid;
}
#article-container a:not(.headerlink, .fancybox):hover {
color: #fff;
border-radius: 5px;
text-decoration: none;
background-color: var(--hao-purple);
}
#danmu {
width: 100%;
height: calc(100% - 60px);
position: fixed;
left: 0;
top: 60px;
z-index: 1;
pointer-events: none;
}
.hidedanmu {
opacity: 0;
}
.hidedanmu * {
pointer-events: none !important;
}
div#danmuBtn {
display: flex;
justify-content: center;
margin: 20px;
}
div#danmuBtn button {
background: var(--hao-purple);
color: white;
padding: 8px 20px;
margin: 0 20px;
border-radius: 100px;
}
.default-style {
pointer-events: all;
cursor: pointer;
display: flex;
justify-content: center;
align-items: center;
font-size: 16px;
border-radius: 100px;
background-color: rgba(0, 0, 0, 0.5);
padding: 6px 16px 6px 6px;
color: #eee;
}
.default-style:hover {
background-color: rgba(0, 0, 0, 0.7);
transition: .3s
}
.default-style img {
pointer-events: none;
height: 30px;
width: 30px;
margin: 0 5px 0 0 !important;
border-radius: 50%;
}
.default-style p {
line-height: 1;
pointer-events: none;
margin: 0 !important;
max-width: 300px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
</style>
</th:block>
// 格式化评论
function formatDanmaku(str) {
str = str.replace(/<\/*br>|[\s\uFEFF\xA0]+/g, '');
str = str.replace(/<img.*?>/g, '[图片]');
str = str.replace(/<a.*?>.*?<\/a>/g, '[链接]');
str = str.replace(/<pre.*?>.*?<\/pre>/g, '[代码块]');
str = str.replace(/<.*?>/g, '');
return str
}
</script>
<hr>
<!--/* 评论组件 */-->
<th:block
th:replace="~{modules/comment :: comment(group = 'content.halo.run',
<th:block th:replace="~{modules/comment :: comment(group = 'content.halo.run',
kind = 'SinglePage',
name = ${singlePage.metadata.name},
allowComment = ${singlePage.spec.allowComment})}"/>
allowComment = ${singlePage.spec.allowComment})}" />
</div>

View File

@ -53,7 +53,7 @@
<div id="random-post"></div>
<script type="text/javascript">
var fdataUser = {
apiurl: [[${ theme.config.fcircle.apiurl }]],
apiurl: [(${ theme.config.fcircle.apiurl })],
defaultFish: 500,
hungryFish: 500,
}

View File

@ -111,6 +111,8 @@
<div id="js-pjax"></div>
<script th:if="${theme.config.envelope_comment.enable_danmu}" th:src="${assets_link + '/libs/twikoo/easy-Danmaku.js'}" id="Danmaku"></script>
<script>
let pjaxSelectors = ['title', '#config-diff', '#body-wrap', '#rightside-config-hide', '#rightside-config-show', '.js-pjax','#site-config']
@ -244,6 +246,13 @@
halo.dataCodeTheme()
}
if(document.querySelector('#danmu') &&
document.body.clientWidth > 768 &&
[[${theme.config.envelope_comment.enable_danmu}]]){
halo.closeCommentBarrage();
halo.addScript("Danmaku", "[[${assets_link + '/libs/twikoo/easy-Danmaku.js'}]]", halo.danmu("[(${theme.config.comments.twikoos.envId})]","[(${theme.config.comments.twikoos.accessToken})]",[[${theme.config.envelope_comment.maxBarrage}]]))
}