菜单
本页目录

增加延迟弹幕显示

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