增加延迟弹幕显示
<th:block th:if="${theme.config.top.above.enable_above}">
<div class="pl-container">
<th:block th:if="!${theme.config.top.above.enable_above_video}">
<div class="pl-img pl-blur pl-visible"
th:style="'background-image: url(' + ${theme.config.top.above.index_img} + ');'">
</div>
<div class="pl-img pl-visible"
th:style="'background-image: url(' + ${theme.config.top.above.phone_index_img} + ');'">
</div>
<video class="video"></video>
</th:block>
<th:block th:if="${theme.config.top.above.enable_above_video}">
<video class="index-video" id="index-video" autoplay=""
th:src="${theme.config.top.above.index_video}" loop="" muted="" playsinline=""
webkit-playsinline=""
style="display:block;object-fit:cover;width:100%;height:100%;pointer-events:none;">
</video>
</th:block>
<!-- 网络延迟显示容器(移至pl-container内部) -->
<div id="network-latency"></div>
</div>
<div id="site-info">
<h1 id="site-title">[[${site.title}]]</h1>
<div id="site-subtitle">
<span id="subtitle"></span>
<span class="typed-cursor" aria-hidden="true"></span>
</div>
<button id="subtitle-link-button" class="subtitle-button" style="display:none;">GO</button>
</div>
<div id="scroll-down"><i class="haofont hao-icon-angle-down scroll-down-effects"></i></div>
<link rel="stylesheet" th:href="${assets_link + '/css/fullPage.css' + theme_version}">
<style>
#site-title {
width: max-content;
max-width: 100%;
position: relative;
color: rgba(255, 255, 255, 0);
animation: 1.5s linear 1s 1 normal both running show;
margin: 0px auto !important;
}
#site-title::after {
content: "";
position: absolute;
left: 0px;
margin: auto;
border-radius: 12px;
top: 11px;
height: 55px;
width: 110%;
animation: 2s cubic-bezier(0.62, 0.21, 0.25, 1) 1.5s 1 normal both running color_change, 2s cubic-bezier(0.62, 0.21, 0.25, 1) 1.5s 1 normal both running swipe_box;
}
@media screen and (max-width: 768px) {
#site-title::after {
background: rgb(255, 255, 255) !important;
}
}
@media screen and (max-width: 768px) {
#site-subtitle::after {
background: rgb(255, 255, 255) !important;
}
}
#site-subtitle {
width: 100%;
max-width: 100%;
position: relative;
animation: 1.5s linear 1s 1 normal both running show;
margin: 0px auto !important;
}
#site-subtitle::after {
content: "";
position: absolute;
left: 0px;
right: 0px;
margin: auto;
border-radius: 12px;
height: 100%;
width: 0%;
animation: 2s cubic-bezier(0.62, 0.21, 0.25, 1) 1.5s 1 normal both running color_change, 2s cubic-bezier(0.62, 0.21, 0.25, 1) 1.5s 1 normal both running swipe_box2;
}
@keyframes color_change {
0% {
background: rgb(255, 255, 255);
}
100% {
background: var(--xlfd-main);
}
}
@-webkit-keyframes color_change {
0% {
background: rgb(255, 255, 255);
}
100% {
background: var(--xlfd-main);
}
}
@-webkit-keyframes swipe_box {
0% {
left: 0px;
width: 0%;
}
50% {
left: 0px;
width: 100%;
}
100% {
left: 100%;
width: 0%;
}
}
@keyframes swipe_box {
0% {
left: 0px;
width: 0%;
}
50% {
left: 0px;
width: 100%;
}
100% {
left: 100%;
width: 0%;
}
}
@-webkit-keyframes swipe_box2 {
0% {
left: 0px;
width: 0%;
}
50% {
left: 0px;
width: 80%;
}
100% {
left: 0px;
width: 0%;
}
}
@keyframes swipe_box2 {
0% {
left: 0px;
width: 0%;
}
50% {
left: 0px;
width: 80%;
}
100% {
left: 0px;
width: 0%;
}
}
@-webkit-keyframes show {
0% {
color: rgba(255, 255, 255, 0);
text-shadow: transparent 2px 3px 10px;
}
81% {
color: rgba(255, 255, 255, 0);
}
100% {
color: rgb(255, 255, 255);
}
}
@keyframes show {
0% {
color: rgba(255, 255, 255, 0);
text-shadow: transparent 2px 3px 10px;
}
81% {
color: rgba(255, 255, 255, 0);
}
100% {
color: rgb(255, 255, 255);
}
}
.pl-img {
background-size: cover;
background-position: center;
height: 100vh;
}
@media screen and (max-width: 768px) {
.pl-img {
background-image: url([[${theme.config.top.above.phone_index_img}]]);
}
}
.typed-cursor {
opacity: 1;
}
.typed-cursor.typed-cursor--blink {
animation: typedjsBlink 0.7s infinite;
-webkit-animation: typedjsBlink 0.7s infinite;
animation: typedjsBlink 0.7s infinite;
}
@keyframes typedjsBlink {
50% {
opacity: 0.0;
}
}
@-webkit-keyframes typedjsBlink {
0% {
opacity: 1;
}
50% {
opacity: 0.0;
}
100% {
opacity: 1;
}
}
/* From www.lingdaima.com */
.subtitle-button {
width: 6.5em;
height: 2.3em;
margin: 0.5em;
background: var(--heo-theme);
color: white;
border: none;
border-radius: 0.625em;
font-size: 20px;
font-weight: bold;
cursor: pointer;
position: relative;
z-index: 1;
overflow: hidden;
margin: 0 auto;
}
.subtitle-button:hover {
color: black;
}
.subtitle-button:after {
content: "";
background: white;
position: absolute;
z-index: -1;
left: -20%;
right: -20%;
top: 0;
bottom: 0;
transform: skewX(-45deg) scale(0, 1);
transition: all 0.5s;
}
.subtitle-button:hover:after {
transform: skewX(-45deg) scale(1, 1);
-webkit-transition: all 0.5s;
transition: all 0.5s;
}
/* 关键修改:pl-container设置相对定位,作为延迟组件的定位参考 */
.pl-container {
position: relative;
min-height: 100vh; /* 确保容器至少占满视口高度 */
}
/* 网络延迟显示样式(修改后) */
#network-latency {
position: absolute; /* 相对于pl-container绝对定位 */
right: 20px; /* 右下角定位 */
bottom: 20px;
z-index: 9999;
font-family: 'Courier New', monospace;
font-size: 14px;
color: #fff;
display: flex;
flex-direction: column;
align-items: flex-end;
gap: 4px;
pointer-events: none;
}
/* 单个延迟记录 */
.latency-item {
padding: 2px 8px;
border-radius: 3px;
white-space: nowrap;
opacity: 1;
transform: translateY(0);
transition: all 0.5s ease-out;
}
/* 不同延迟等级的文字颜色 */
.latency-item.low { color: #00ff00; }
.latency-item.medium { color: #ffff00; }
.latency-item.high { color: #ff0000; }
.latency-item.error { color: #ff9900; }
/* 动画效果 */
.latency-item.entering {
opacity: 0;
transform: translateY(20px);
}
.latency-item.exiting {
opacity: 0;
transform: translateY(-20px);
}
/* 移动端适配 */
@media (max-width: 768px) {
#network-latency {
right: 10px;
bottom: 10px;
font-size: 12px;
gap: 2px;
}
}
</style>
<script th:inline="javascript">
function subtitleType() {
if ([[${theme.config.top.above.enable_typed_random}]]) {
fetch("https://v1.hitokoto.cn/?c=a&b=c").then((t => t.json())).then((t => {
const baseUrl = "https://mzh.moegirl.org.cn/";
const linkUrl = baseUrl + t.from;
const e = "出自 " + t.from;
const n = [[${theme.config.top.above.typed}]].map((item) => {
return item.realNode.text;
});
n.push(t.hitokoto, e);
window.typed = new Typed("#subtitle", {
strings: n,
startDelay: 300,
typeSpeed: 100,
loop:!0,
backSpeed: 50
});
const button = document.getElementById('subtitle-link-button');
button.style.display = 'block';
button.addEventListener('click', function () {
window.open(linkUrl, '_blank');
});
}))
} else {
const n = [[${theme.config.top.above.typed}]].map((item) => {
return item.realNode.text;
});
window.typed = new Typed("#subtitle", {
strings: n,
startDelay: 300,
typeSpeed: 100,
loop:!0,
backSpeed: 50
});
}
}
// 防止加载文字太短时第一个自定义文字显示不出来
setTimeout(() => {
"function" == typeof Typed ? subtitleType() : getScript("https://npm.elemecdn.com/typed.js@2.0.12/lib/typed.min.js").then(subtitleType)
}, 1800)
// 网络延迟测量功能(保持不变)
document.addEventListener('DOMContentLoaded', function() {
const container = document.getElementById('network-latency');
let latencyItems = [];
// 获取延迟等级
function getLatencyClass(latency) {
if (latency === '—') return 'error';
if (latency < 150) return 'low';
if (latency < 300) return 'medium';
return 'high';
}
// 添加新的延迟记录
function addLatency(latency) {
const latencyClass = getLatencyClass(latency);
// 创建新记录元素
const item = document.createElement('div');
item.className = `latency-item ${latencyClass} entering`;
item.textContent = `延迟: ${latency}ms`;
container.appendChild(item);
// 触发进入动画
setTimeout(() => {
item.classList.remove('entering');
}, 10);
// 添加到数组
latencyItems.push(item);
// 限制最多显示5条记录
if (latencyItems.length > 5) {
const oldestItem = latencyItems.shift();
oldestItem.classList.add('exiting');
// 动画结束后移除
setTimeout(() => {
container.removeChild(oldestItem);
}, 500);
}
}
// 测量网络延迟
function measureLatency() {
const startTime = performance.now();
const testUrls = [
'https://www.google.com/generate_204',
'https://cloudflare.com/cdn-cgi/trace',
'https://www.cloudflare.com/robots.txt'
];
const randomUrl = testUrls[Math.floor(Math.random() * testUrls.length)];
fetch(randomUrl, {
method: 'HEAD',
cache: 'no-cache',
mode: 'no-cors',
credentials: 'omit'
})
.then(response => {
const latency = Math.round(performance.now() - startTime);
addLatency(latency);
container.style.display = 'flex';
})
.catch(() => {
addLatency('—');
container.style.display = 'flex';
});
}
// 初始测量和定时更新
measureLatency();
setInterval(measureLatency, 3000);
});
</script>
</th:block>