网页加载分析(改)

测试网页加载速度并显示加载最慢的三个网址的域名,二改添加了对Via浏览器toast的调用,添加高斯模糊效果。

目前為 2025-04-16 提交的版本,檢視 最新版本

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

You will need to install an extension such as Tampermonkey to install this script.

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==UserScript==
// @name         网页加载分析(改)
// @version      1.14
// @description  测试网页加载速度并显示加载最慢的三个网址的域名,二改添加了对Via浏览器toast的调用,添加高斯模糊效果。
// @description:en Test the webpage loading speed and display the domain names of the three slowest loading URLs.
// @match        *://*/*
// @run-at       document-start
// @author       yzcjd & nobody
// @author2      Lama AI 辅助
// @namespace    https://scriptcat.org/zh-CN/users/157252
// @exclude      *://*.cloudflare.com/*
// @exclude      *://*.recaptcha.net/*
// @license      MIT
// @grant        GM_setValue
// @grant        GM_getValue
// @grant        GM_registerMenuCommand
// ==/UserScript==

(function() {
    'use strict';

    const currentDomain = location.hostname || 'unknown';
    // 检查是否在 GM 环境中
    const isGMEnvironment = typeof GM_getValue === 'function' && typeof GM_setValue === 'function' && typeof GM_registerMenuCommand === 'function';

    // 初始化设置
    let isEnabled = true; // 默认启用网页加载测试
    let useBlurDisplay = true; // 默认使用高斯模糊显示
    let domainSettings = {};

    if (isGMEnvironment) {
        domainSettings = GM_getValue('domainSettings', {});
        isEnabled = domainSettings[currentDomain] !== false;
        useBlurDisplay = GM_getValue('useBlurDisplay', false);

        GM_registerMenuCommand(
            `${isEnabled ? '❌禁用' : '✅启用'} 网页加载测试(${currentDomain})`,
            () => {
                domainSettings[currentDomain] = !isEnabled;
                GM_setValue('domainSettings', domainSettings);
                alert(`网页加载测试已${!isEnabled ? '✅启用' : '❌禁用'}(${currentDomain}),刷新页面生效。`);
            }
        );
        GM_registerMenuCommand(
            `${useBlurDisplay ? '❌禁用' : '✅启用'} 高斯模糊显示`,
            () => {
                GM_setValue('useBlurDisplay', !useBlurDisplay);
                alert(`高斯模糊显示已${!isEnabled ? '✅启用' : '❌禁用'},刷新页面生效。`);
            }
        );
        if (!isEnabled) return;
    }

    const loadTimeElement = document.createElement('div');
    loadTimeElement.id = 'loadTimeDisplay';
    loadTimeElement.style.cssText = `
        position: fixed;
        top: 85%;
        left: 50%;
        transform: translate(-50%, -50%);
        background: rgba(255, 255, 255, 0.3); /* 半透明毛玻璃背景 */
        backdrop-filter: blur(16px); /* 高斯模糊 */
        -webkit-backdrop-filter: blur(16px); /* 兼容 Safari */
        padding: 12px 20px; /* 舒适内边距 */
        border-radius: 22px; /* iOS 风格圆角 */
        box-shadow: 0 6px 24px rgba(0, 0, 0, 0.15); /* 柔和阴影 */
        white-space: nowrap;
        width: auto; /* 自适应宽度 */
        max-width: 90%; /* 防止溢出 */
        z-index: 9999;
        color: #1C2526; /* 深色文字,确保可读 */
        font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; /* iOS 字体 */
        font-size: 15px; /* 优雅字体大小 */
        font-weight: 500; /* 适中字重 */
        text-align: center; /* 文字居中 */
        border: 1px solid rgba(255, 255, 255, 0.25); /* 微弱边框增加质感 */
        opacity: 0; /* 初始透明 */
        transition: opacity 0.3s ease-in-out; /* 淡入动画 */
    `;

    // 兼容不支持 backdrop-filter 的浏览器
    if (!CSS.supports('backdrop-filter', 'blur(16px)')) {
        loadTimeElement.style.background = 'rgba(240, 240, 240, 0.85)';
    }

    const startTime = performance.now();
    const slowestRequests = new Set();
    const maxSlowRequests = 3;

    const networkObserver = new PerformanceObserver((list) => {
        list.getEntries().forEach((entry) => {
            slowestRequests.add({
                name: entry.name,
                duration: entry.duration,
            });
            if (slowestRequests.size > maxSlowRequests) {
                const sorted = Array.from(slowestRequests).sort((a, b) => b.duration - a.duration);
                slowestRequests.clear();
                sorted.slice(0, maxSlowRequests).forEach((req) => slowestRequests.add(req));
            }
        });
    });

    networkObserver.observe({
        entryTypes: ['resource']
    });

    window.addEventListener('load', () => {
        networkObserver.disconnect();
        const endTime = performance.now();
        const timeElapsed = endTime - startTime;
        const sortedRequests = Array.from(slowestRequests).sort((a, b) => b.duration - a.duration);

        const networkInfoHTML = sortedRequests.length ?
            sortedRequests
            .map((req) => {
                try {
                    const url = new URL(req.name);
                    return `slow: ${url.hostname} (${req.duration.toFixed(2)}ms)<br>`;
                } catch {
                    return `slow: Invalid URL (${req.duration.toFixed(2)}ms)<br>`;
                }
            })
            .join('') :
            '[none]';

        const networkInfo = sortedRequests.length ?
            sortedRequests
            .map((req) => {
                try {
                    const url = new URL(req.name);
                    return `Slow: ${url.hostname} (${req.duration.toFixed(2)}ms)`;
                } catch {
                    return `Slow: Invalid URL (${req.duration.toFixed(2)}ms)`;
                }
            })
            .join('\n') :
            '[none]';

        if (window.via && typeof window.via.toast === 'function' && !useBlurDisplay) {
            window.via.toast(`Time: ${timeElapsed.toFixed(2)}ms\n${networkInfo}`);
        } else {
            loadTimeElement.innerHTML = `<h2 style="margin:0;font-size:16px;font-weight:600">Time: ${timeElapsed.toFixed(2)}ms</h2>${networkInfoHTML}`;
            document.body.appendChild(loadTimeElement);
            requestAnimationFrame(() => {
                loadTimeElement.style.opacity = '1';
            });
            setTimeout(() => {
                requestAnimationFrame(() => {
                    loadTimeElement.style.opacity = '0';
                });
                setTimeout(() => loadTimeElement.remove(), 300);
            }, 2600);
        }

        slowestRequests.clear();
    });
})();