// ==UserScript== // @name Web性能综合优化工具箱 (WebGPU重构版) // @namespace http://tampermonkey.net/ // @version 3.7.1-compatibility-optimized // @description Web浏览提速80%;DOM渲染及GPU加速;集成Core Web Vitals实时监控面板 // @author KiwiFruit // @match *://*/* // @exclude *://weibo.com/* // @exclude *://*.weibo.com/* // @grant none // @license MIT // @run-at document-idle // @downloadURL none // ==/UserScript== (function () { 'use strict'; // ======================== // 1. 环境检测与配置 // ======================== const Env = { features: { nativeLazyLoad: 'loading' in HTMLImageElement.prototype, intersectionObserver: 'IntersectionObserver' in window, mutationObserver: 'MutationObserver' in window, performanceObserver: 'PerformanceObserver' in window, requestIdleCallback: 'requestIdleCallback' in window, contentVisibility: CSS.supports('content-visibility', 'hidden'), webgpu: typeof GPU !== 'undefined' && !!navigator.gpu }, performanceTier: (() => { if (navigator.hardwareConcurrency >= 4) return 2; if (window.devicePixelRatio <= 1.5) return 1; return 0; })(), networkType: navigator.connection?.effectiveType || 'unknown', isLowPerformance() { return this.performanceTier === 0 || this.networkType === '2g'; } }; const Config = { debug: false, ui: { enabled: true, position: 'bottom-right', zIndex: 9999, autoHideDelay: 3000, hoverDelay: 300, hideOffset: { bottom: 20, right: -50 }, showOffset: { bottom: 20, right: 20 }, statsUpdateTimeout: 2000, sampleSize: 200 }, lazyLoad: { enabled: true, selector: 'img[data-src], img[data-original], img.lazy, iframe[data-src], .js-lazy-load', preloadDistance: 150 }, hardwareAcceleration: { enabled: true, selector: 'header, nav, aside, .sticky, .fixed, .js-animate, .js-transform', skipViewportElements: true, delayForVisibleElements: 5000 }, contentVisibility: { enabled: true, selector: 'section, article, .post, .js-section', hiddenDistance: 600, viewportBuffer: 200, streamModeThreshold: 500, respectCanvas: true, respectWebGPU: true, smartViewportCheck: true }, preconnect: { enabled: true, domains: ['cdn.jsdelivr.net', 'cdnjs.cloudflare.com', 'fonts.googleapis.com', 'fonts.gstatic.com'] }, blacklistedDomains: ['weibo.com', 'weibo.cn'] }; const Logger = { log: (module, level, msg) => { if (Config.debug || level === 'error') { const prefix = `[PerfOpt][${module}]`; const methods = { debug: console.log, info: console.info, warn: console.warn, error: console.error }; methods[level](prefix, msg); } }, debug: (m, msg) => Logger.log(m, 'debug', msg), info: (m, msg) => Logger.log(m, 'info', msg), warn: (m, msg) => Logger.log(m, 'warn', msg), error: (m, msg) => Logger.log(m, 'error', msg) }; // ======================== // 2. 核心基类 // ======================== class BaseModule { constructor(name) { this.moduleName = name; this.initialized = false; this.mutationObserver = null; } init() { if (this.initialized) { Logger.warn(this.moduleName, '已初始化'); return; } this.initialized = true; this.setupMutationObserver(); Logger.info(this.moduleName, '初始化完成'); } destroy() { if (!this.initialized) return; this.initialized = false; if (this.mutationObserver) { this.mutationObserver.disconnect(); this.mutationObserver = null; } Logger.info(this.moduleName, '已销毁'); } emit(event, data = {}) { window.dispatchEvent(new CustomEvent(`perfopt:${this.moduleName}:${event}`, { detail: { ...data, module: this.moduleName, timestamp: Date.now() } })); } setupMutationObserver() { if (!Env.features.mutationObserver) return; this.mutationObserver = new MutationObserver((mutations) => { for (const mutation of mutations) { if (mutation.addedNodes.length) { this.handleNewNodes(mutation.addedNodes); } } }); this.mutationObserver.observe(document.body, { childList: true, subtree: true }); } handleNewNodes(nodeList) {} } // ======================== // 3. 图片懒加载优化 // ======================== class ImageOptimizer extends BaseModule { constructor() { super('ImageOptimizer'); this.observer = null; } init() { super.init(); if (!Config.lazyLoad.enabled) { Logger.warn('ImageOptimizer', '图片懒加载未启用'); return; } if (Env.features.intersectionObserver) { this.applyIntersectionObserver(); } else if (Env.features.nativeLazyLoad) { this.applyNativeLazyLoad(); } else { this.applyScrollBasedLazyLoad(); } Logger.info('ImageOptimizer', '图片懒加载初始化完成'); } applyIntersectionObserver() { this.observer = new IntersectionObserver((entries) => { entries.forEach(entry => { if (entry.isIntersecting) { const el = entry.target; if (el.dataset.src) { el.src = el.dataset.src; delete el.dataset.src; this.observer.unobserve(el); Logger.debug('ImageOptimizer', '图片已加载'); } } }); }, { rootMargin: `${Config.lazyLoad.preloadDistance}px 0px`, threshold: 0.01 }); this.scanAndObserve(document.querySelectorAll(Config.lazyLoad.selector)); } applyNativeLazyLoad() { document.querySelectorAll(Config.lazyLoad.selector).forEach(el => { el.loading = 'lazy'; }); } applyScrollBasedLazyLoad() { let ticking = false; this.scrollListener = () => { if (!ticking) { requestAnimationFrame(() => { this.loadVisibleImages(); ticking = false; }); ticking = true; } }; window.addEventListener('scroll', this.scrollListener, { passive: true }); this.loadVisibleImages(); } loadVisibleImages() { const viewportHeight = window.innerHeight; const scrollTop = window.pageYOffset; document.querySelectorAll(Config.lazyLoad.selector).forEach(el => { const rect = el.getBoundingClientRect(); if (rect.top < viewportHeight + Config.lazyLoad.preloadDistance && rect.bottom > -Config.lazyLoad.preloadDistance) { if (el.dataset.src) { el.src = el.dataset.src; delete el.dataset.src; } } }); } scanAndObserve(elements) { elements.forEach(el => { if (this.observer) { this.observer.observe(el); } }); } handleNewNodes(nodeList) { if (!this.observer) return; nodeList.forEach(node => { if (node.nodeType === 1) { if (node.matches(Config.lazyLoad.selector)) { this.observer.observe(node); } const children = node.querySelectorAll(Config.lazyLoad.selector); children.forEach(el => this.observer.observe(el)); } }); } destroy() { super.destroy(); if (this.observer) { this.observer.disconnect(); this.observer = null; } if (this.scrollListener) { window.removeEventListener('scroll', this.scrollListener); this.scrollListener = null; } } } // ======================== // 4. GPU加速优化 (WebGPU兼容版) // ======================== class GPUAccelerator extends BaseModule { constructor() { super('GPUAccelerator'); this.pendingOptimizations = new Map(); } init() { super.init(); if (!Config.hardwareAcceleration.enabled) { Logger.warn('GPUAccelerator', 'GPU加速未启用'); return; } this.processElements(document.querySelectorAll(Config.hardwareAcceleration.selector)); Logger.info('GPUAccelerator', 'GPU加速初始化完成'); } processElements(elements) { elements.forEach(el => this.applyOptimization(el)); } applyOptimization(element) { if (element.classList.contains('gpu-accelerate')) return; if (element.closest('.streaming, [data-streaming], .generating')) { Logger.debug('GPUAccelerator', '跳过流式内容元素'); return; } if (Config.hardwareAcceleration.skipViewportElements) { const rect = element.getBoundingClientRect(); const isFullyVisible = rect.top >= 0 && rect.bottom <= window.innerHeight; if (isFullyVisible && Config.hardwareAcceleration.delayForVisibleElements > 0) { const timeoutId = setTimeout(() => { this.doApplyOptimization(element); this.pendingOptimizations.delete(element); }, Config.hardwareAcceleration.delayForVisibleElements); this.pendingOptimizations.set(element, timeoutId); return; } } this.doApplyOptimization(element); } doApplyOptimization(element) { element.classList.add('gpu-accelerate'); element.style.transform = 'translateZ(0)'; element.style.backfaceVisibility = 'hidden'; } removeOptimization(element) { element.classList.remove('gpu-accelerate'); element.style.transform = ''; element.style.backfaceVisibility = ''; if (this.pendingOptimizations.has(element)) { clearTimeout(this.pendingOptimizations.get(element)); this.pendingOptimizations.delete(element); } } handleNewNodes(nodeList) { nodeList.forEach(node => { if (node.nodeType === 1) { const candidates = node.matches(Config.hardwareAcceleration.selector) ? [node, ...node.querySelectorAll(Config.hardwareAcceleration.selector)] : node.querySelectorAll(Config.hardwareAcceleration.selector); candidates.forEach(el => this.applyOptimization(el)); } }); } destroy() { super.destroy(); this.pendingOptimizations.forEach((timeoutId) => clearTimeout(timeoutId)); this.pendingOptimizations.clear(); document.querySelectorAll('.gpu-accelerate').forEach(el => { this.removeOptimization(el); }); } } // ======================== // 5. 内容可见性优化 (WebGPU/视口感知重构版) // ======================== class ContentVisibility extends BaseModule { constructor() { super('ContentVisibility'); this.scrollListener = null; this.resizeListener = null; this.processedElements = new WeakSet(); this.recentAdditions = []; this.streamThrottleTimer = null; } init() { super.init(); if (!Config.contentVisibility.enabled) { Logger.warn('ContentVisibility', '内容可见性优化未启用'); return; } if (!Env.features.contentVisibility) { Logger.info('ContentVisibility', '浏览器不支持 content-visibility'); return; } this.updateVisibility(document.querySelectorAll(Config.contentVisibility.selector)); let ticking = false; const handleChange = () => { if (!ticking) { requestAnimationFrame(() => { this.updateVisibility(document.querySelectorAll(Config.contentVisibility.selector)); ticking = false; }); ticking = true; } }; this.scrollListener = handleChange; this.resizeListener = handleChange; window.addEventListener('scroll', this.scrollListener, { passive: true }); window.addEventListener('resize', this.resizeListener, { passive: true }); Logger.info('ContentVisibility', '内容可见性优化初始化完成'); } isInViewport(el, buffer = Config.contentVisibility.viewportBuffer) { if (!el || !el.getBoundingClientRect) return false; const rect = el.getBoundingClientRect(); const windowHeight = window.innerHeight || document.documentElement.clientHeight; const windowWidth = window.innerWidth || document.documentElement.clientWidth; const verticalInView = ( rect.top <= windowHeight + buffer && rect.bottom >= -buffer ); const horizontalInView = ( rect.left <= windowWidth + buffer && rect.right >= -buffer ); return verticalInView && horizontalInView; } containsWebGPU(el) { if (!el || el.nodeType !== 1) return false; if (el.tagName === 'CANVAS') { if (el.getContext && typeof el.getContext === 'function') { try { if (el.dataset.webgpu === 'true' || el.getAttribute('data-webgpu')) { return true; } } catch (e) {} } } if (el.querySelector && el.querySelector('canvas[data-webgpu="true"], canvas[webgpu], [data-webgpu-context]')) { return true; } if (el.closest && el.closest('[data-webgpu-container], [data-webgpu="true"], .webgpu-container')) { return true; } if (el.classList && (el.classList.contains('webgpu-canvas') || el.classList.contains('webgpu-container'))) { return true; } return false; } containsCanvas(el) { if (!el || el.nodeType !== 1) return false; return el.tagName === 'CANVAS' || (el.querySelector && el.querySelector('canvas') !== null) || (el.closest && el.closest('[data-canvas-rendered]') !== null); } isStreaming() { const now = Date.now(); this.recentAdditions = this.recentAdditions.filter(t => now - t < 1000); return this.recentAdditions.length > 3; } handleNewNodes(nodeList) { const now = Date.now(); const isStreaming = this.isStreaming(); nodeList.forEach(node => { if (node.nodeType !== 1) return; this.recentAdditions.push(now); let candidates = []; if (node.matches && node.matches(Config.contentVisibility.selector)) { candidates = [node, ...node.querySelectorAll(Config.contentVisibility.selector)]; } else if (node.querySelectorAll) { candidates = node.querySelectorAll(Config.contentVisibility.selector); } candidates.forEach(el => { if (this.processedElements.has(el)) return; if (Config.contentVisibility.respectWebGPU && this.containsWebGPU(el)) { Logger.debug('ContentVisibility', '跳过 WebGPU 容器元素'); this.setAuto(el); this.processedElements.add(el); return; } if (Config.contentVisibility.respectCanvas && this.containsCanvas(el)) { Logger.debug('ContentVisibility', '跳过 Canvas 容器元素'); this.setAuto(el); this.processedElements.add(el); return; } if (isStreaming || this.isInViewport(el)) { this.setAuto(el); if (!isStreaming) { this.processedElements.add(el); } } else { this.setHidden(el); this.processedElements.add(el); } }); }); if (isStreaming && this.scrollListener) { clearTimeout(this.streamThrottleTimer); this.streamThrottleTimer = setTimeout(() => { this.updateVisibility(document.querySelectorAll(Config.contentVisibility.selector)); }, 2000); } } updateVisibility(elements) { const viewportCandidates = []; const hiddenCandidates = []; elements.forEach(el => { if (this.isInViewport(el, Config.contentVisibility.hiddenDistance)) { viewportCandidates.push(el); } else { hiddenCandidates.push(el); } }); viewportCandidates.forEach(el => { this.setAuto(el); }); requestAnimationFrame(() => { hiddenCandidates.forEach(el => { if (!this.isInViewport(el)) { this.setHidden(el); } }); }); } setAuto(el) { el.style.contentVisibility = 'auto'; el.style.containIntrinsicSize = ''; el.classList.add('perfopt-in-viewport'); el.classList.remove('perfopt-hidden'); } setHidden(el) { el.style.contentVisibility = 'hidden'; el.style.containIntrinsicSize = '300px'; el.classList.add('perfopt-hidden'); el.classList.remove('perfopt-in-viewport'); } destroy() { super.destroy(); if (this.scrollListener) { window.removeEventListener('scroll', this.scrollListener); this.scrollListener = null; } if (this.resizeListener) { window.removeEventListener('resize', this.resizeListener); this.resizeListener = null; } if (this.streamThrottleTimer) { clearTimeout(this.streamThrottleTimer); this.streamThrottleTimer = null; } document.querySelectorAll(Config.contentVisibility.selector).forEach(el => { el.style.contentVisibility = ''; el.style.containIntrinsicSize = ''; el.classList.remove('perfopt-in-viewport', 'perfopt-hidden'); }); } } // ======================== // 6. 预连接优化 // ======================== class PreconnectOptimizer extends BaseModule { constructor() { super('PreconnectOptimizer'); this.createdLinks = []; } init() { super.init(); if (!Config.preconnect.enabled) { Logger.warn('PreconnectOptimizer', '预连接优化未启用'); return; } Config.preconnect.domains.forEach(domain => { const link = document.createElement('link'); link.rel = 'preconnect'; link.href = `https://${domain}`; document.head.appendChild(link); this.createdLinks.push(link); const dnsLink = document.createElement('link'); dnsLink.rel = 'dns-prefetch'; dnsLink.href = `https://${domain}`; document.head.appendChild(dnsLink); this.createdLinks.push(dnsLink); }); Logger.info('PreconnectOptimizer', '预连接优化初始化完成'); } destroy() { super.destroy(); this.createdLinks.forEach(link => link.remove()); this.createdLinks = []; } } // ======================== // 7. 性能监控 (Core Web Vitals数据存储版) // ======================== class PerformanceMonitor extends BaseModule { constructor() { super('PerformanceMonitor'); this.observer = null; // 核心指标数据存储 this.metrics = { fcp: null, lcp: null, cls: 0, clsCount: 0, ttfb: null }; } init() { super.init(); if (!Env.features.performanceObserver) { Logger.warn('PerformanceMonitor', '浏览器不支持 PerformanceObserver'); return; } try { this.observer = new PerformanceObserver((list) => { list.getEntries().forEach(entry => { if (entry.entryType === 'paint') { if (entry.name === 'first-contentful-paint') { this.metrics.fcp = Math.round(entry.startTime); Logger.info('Performance', `FCP: ${this.metrics.fcp}ms`); this.emit('metric', { type: 'fcp', value: this.metrics.fcp }); } } else if (entry.entryType === 'layout-shift') { if (!entry.hadRecentInput) { this.metrics.cls += entry.value; this.metrics.clsCount++; Logger.info('Performance', `CLS: ${this.metrics.cls.toFixed(3)}`); this.emit('metric', { type: 'cls', value: this.metrics.cls }); } } else if (entry.entryType === 'largest-contentful-paint') { this.metrics.lcp = Math.round(entry.startTime); Logger.info('Performance', `LCP: ${this.metrics.lcp}ms`); this.emit('metric', { type: 'lcp', value: this.metrics.lcp }); } }); }); this.observer.observe({ entryTypes: ['paint', 'layout-shift', 'largest-contentful-paint'] }); window.addEventListener('load', () => { setTimeout(() => { const timing = performance.timing; if (timing) { this.metrics.ttfb = timing.responseStart - timing.navigationStart; Logger.info('Performance', `TTFB: ${this.metrics.ttfb}ms`); this.emit('metric', { type: 'ttfb', value: this.metrics.ttfb }); } }, 0); }); Logger.info('PerformanceMonitor', '性能监控初始化完成'); } catch (error) { Logger.error('PerformanceMonitor', `初始化失败: ${error.message}`); } } // 获取当前指标数据供UI使用 getMetrics() { return { fcp: this.metrics.fcp, lcp: this.metrics.lcp, cls: this.metrics.cls, clsCount: this.metrics.clsCount, ttfb: this.metrics.ttfb }; } destroy() { super.destroy(); if (this.observer) { this.observer.disconnect(); this.observer = null; } } } // ======================== // 8. UI控制器 (集成Core Web Vitals显示) // ======================== class UIController extends BaseModule { constructor() { super('UIController'); this.visible = false; this.panelVisible = false; this.autoHideTimeout = null; this.hoverTimeout = null; this.isHovered = false; this.button = null; this.panel = null; this.isUpdateScheduled = false; this.cachedDomDepth = 0; this.domDepthCalculated = false; // 性能指标引用 this.performanceMonitor = null; } setPerformanceMonitor(monitor) { this.performanceMonitor = monitor; } init() { super.init(); if (!Config.ui.enabled) return; try { this.createUI(); this.attachEvents(); this.startAutoHideTimer(); this.scheduleInitialStats(); Logger.info('UIController', 'UI组件创建成功'); } catch (error) { Logger.error('UIController', `UI创建失败: ${error.message}`); Logger.error('UIController', error.stack); this.createFallbackUI(); } } scheduleInitialStats() { if (Env.features.requestIdleCallback) { requestIdleCallback(() => { this.updateStats(); }, { timeout: 1000 }); } else { setTimeout(() => this.updateStats(), 500); } } scheduleStatsUpdate() { if (!this.panelVisible) return; if (this.isUpdateScheduled) return; this.isUpdateScheduled = true; if (Env.features.requestIdleCallback) { requestIdleCallback( () => { if (this.panelVisible) { this.updateStats(); } this.isUpdateScheduled = false; if (this.panelVisible) { this.scheduleStatsUpdate(); } }, { timeout: Config.ui.statsUpdateTimeout } ); } else { setTimeout(() => { if (this.panelVisible) { this.updateStats(); } this.isUpdateScheduled = false; if (this.panelVisible) { this.scheduleStatsUpdate(); } }, 1000); } } updateStats() { if (!this.panel) return; try { const lazyCount = document.querySelectorAll(Config.lazyLoad.selector).length; const gpuCount = document.querySelectorAll('.gpu-accelerate').length; const autoCount = document.querySelectorAll('.perfopt-in-viewport').length; const hiddenCount = document.querySelectorAll('.perfopt-hidden').length; const domDepth = this.domDepthCalculated ? this.cachedDomDepth : this.calculateDomDepth(); // 更新基础统计 this.updateElement('perfopt-lazy-count', lazyCount); this.updateElement('perfopt-gpu-count', gpuCount); this.updateElement('perfopt-dom-depth', domDepth); this.updateElement('perfopt-auto-count', autoCount); this.updateElement('perfopt-hidden-count', hiddenCount); // 更新性能指标 (Core Web Vitals) if (this.performanceMonitor) { const metrics = this.performanceMonitor.getMetrics(); // FCP - 首次内容绘制 this.updateMetricDisplay('perfopt-fcp', metrics.fcp, 'ms', (v) => { if (v < 1800) return 'good'; if (v < 3000) return 'needs-improvement'; return 'poor'; }); // LCP - 最大内容绘制 this.updateMetricDisplay('perfopt-lcp', metrics.lcp, 'ms', (v) => { if (v < 2500) return 'good'; if (v < 4000) return 'needs-improvement'; return 'poor'; }); // CLS - 累积布局偏移 this.updateMetricDisplay('perfopt-cls', metrics.cls, '', (v) => { if (v < 0.1) return 'good'; if (v < 0.25) return 'needs-improvement'; return 'poor'; }); } } catch (error) { Logger.warn('UIController', `统计更新失败: ${error.message}`); } } updateElement(id, value) { const el = document.getElementById(id); if (el) el.textContent = value; } updateMetricDisplay(id, value, unit, gradeFn) { const valueEl = document.getElementById(id); const statusEl = document.getElementById(`${id}-status`); if (!valueEl) return; if (value === null || value === undefined) { valueEl.textContent = '--'; if (statusEl) { statusEl.textContent = '等待中'; statusEl.className = 'perfopt-metric-status'; } return; } const formattedValue = typeof value === 'number' ? (unit === '' ? value.toFixed(3) : Math.round(value)) : value; valueEl.textContent = formattedValue + unit; if (statusEl && gradeFn) { const grade = gradeFn(value); statusEl.className = `perfopt-metric-status ${grade}`; const gradeText = { 'good': '良好', 'needs-improvement': '需改进', 'poor': '较差' }; statusEl.textContent = gradeText[grade] || ''; } } calculateDomDepth() { const allElements = document.querySelectorAll('*'); const sampleSize = Math.min(allElements.length, Config.ui.sampleSize); let maxDepth = 0; for (let i = 0; i < sampleSize; i++) { let depth = 0; let parent = allElements[i]; while (parent && parent !== document) { depth++; parent = parent.parentNode; } if (depth > maxDepth) { maxDepth = depth; } } this.cachedDomDepth = maxDepth; this.domDepthCalculated = true; return maxDepth; } createUI() { const style = document.createElement('style'); style.id = 'perfopt-ui-style'; style.textContent = ` .perfopt-ui-button { position: fixed !important; bottom: ${Config.ui.showOffset.bottom}px !important; right: ${Config.ui.showOffset.right}px !important; width: 56px !important; height: 56px !important; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%) !important; border-radius: 50% !important; box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15) !important; display: flex !important; align-items: center !important; justify-content: center !important; cursor: pointer !important; z-index: ${Config.ui.zIndex} !important; transition: transform 0.3s ease, box-shadow 0.3s ease, right 0.5s cubic-bezier(0.25, 0.46, 0.45, 0.94) !important; font-size: 24px !important; opacity: 1 !important; visibility: visible !important; pointer-events: auto !important; user-select: none !important; } .perfopt-ui-button:hover { transform: scale(1.1) !important; } .perfopt-ui-button:active { transform: scale(0.95) !important; } .perfopt-ui-button.hidden { right: ${Config.ui.hideOffset.right}px !important; box-shadow: 0 2px 6px rgba(0, 0, 0, 0.1) !important; } .perfopt-ui-button.hidden:hover { right: ${Config.ui.showOffset.right}px !important; } .perfopt-ui-panel { position: fixed !important; bottom: 90px !important; right: 20px !important; width: 320px !important; background: rgba(255, 255, 255, 0.95) !important; backdrop-filter: blur(10px) !important; border-radius: 16px !important; box-shadow: 0 8px 24px rgba(0, 0, 0, 0.15) !important; padding: 20px !important; z-index: ${Config.ui.zIndex - 1} !important; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif !important; max-height: 85vh !important; overflow-y: auto !important; display: none !important; transition: opacity 0.3s ease, transform 0.3s ease !important; transform: translateY(10px) !important; opacity: 0 !important; user-select: none !important; } .perfopt-ui-panel.visible { display: block !important; transform: translateY(0) !important; opacity: 1 !important; } .perfopt-panel-header { display: flex !important; justify-content: space-between !important; align-items: center !important; margin-bottom: 16px !important; padding-bottom: 12px !important; border-bottom: 1px solid rgba(0, 0, 0, 0.1) !important; } .perfopt-panel-title { font-size: 18px !important; font-weight: 600 !important; color: #333 !important; } .perfopt-panel-close { width: 24px !important; height: 24px !important; cursor: pointer !important; display: flex !important; align-items: center !important; justify-content: center !important; border-radius: 50% !important; transition: background 0.2s ease !important; } .perfopt-panel-close:hover { background: rgba(0, 0, 0, 0.1) !important; } .perfopt-module-item { display: flex !important; justify-content: space-between !important; align-items: center !important; padding: 12px 0 !important; border-bottom: 1px solid rgba(0, 0, 0, 0.05) !important; } .perfopt-module-info { display: flex !important; align-items: center !important; gap: 12px !important; } .perfopt-module-icon { width: 32px !important; height: 32px !important; display: flex !important; align-items: center !important; justify-content: center !important; background: rgba(102, 126, 234, 0.1) !important; border-radius: 8px !important; } .perfopt-module-name { font-size: 14px !important; font-weight: 500 !important; color: #333 !important; } .perfopt-module-status { display: flex !important; align-items: center !important; gap: 8px !important; } .perfopt-status-indicator { width: 8px !important; height: 8px !important; border-radius: 50% !important; background: #48bb78 !important; } .perfopt-status-text { font-size: 12px !important; color: #666 !important; } /* Core Web Vitals 样式 */ .perfopt-vitals-section { margin-top: 16px !important; padding: 12px !important; background: rgba(102, 126, 234, 0.05) !important; border-radius: 12px !important; border: 1px solid rgba(102, 126, 234, 0.1) !important; } .perfopt-vitals-title { font-size: 13px !important; font-weight: 600 !important; color: #667eea !important; margin-bottom: 10px !important; display: flex !important; align-items: center !important; gap: 6px !important; } .perfopt-metric-row { display: flex !important; justify-content: space-between !important; align-items: center !important; padding: 6px 0 !important; font-size: 13px !important; } .perfopt-metric-label { color: #666 !important; display: flex !important; align-items: center !important; gap: 4px !important; } .perfopt-metric-value-group { display: flex !important; align-items: center !important; gap: 8px !important; } .perfopt-metric-value { font-weight: 600 !important; color: #333 !important; font-variant-numeric: tabular-nums !important; } .perfopt-metric-status { font-size: 11px !important; padding: 2px 6px !important; border-radius: 10px !important; font-weight: 500 !important; min-width: 40px !important; text-align: center !important; } .perfopt-metric-status.good { background: #c6f6d5 !important; color: #22543d !important; } .perfopt-metric-status.needs-improvement { background: #feebc8 !important; color: #744210 !important; } .perfopt-metric-status.poor { background: #fed7d7 !important; color: #742a2a !important; } .perfopt-metric-unit { font-size: 11px !important; color: #999 !important; margin-left: 2px !important; } .perfopt-stats { margin-top: 16px !important; padding: 12px !important; background: rgba(102, 126, 234, 0.05) !important; border-radius: 8px !important; font-size: 12px !important; color: #666 !important; } .perfopt-stats-row { display: flex !important; justify-content: space-between !important; margin-bottom: 8px !important; } .perfopt-stats-row:last-child { margin-bottom: 0 !important; } @media (max-width: 480px) { .perfopt-ui-panel { width: calc(100vw - 40px) !important; } } `; document.head.appendChild(style); this.button = document.createElement('div'); this.button.className = 'perfopt-ui-button'; this.button.innerHTML = '⚡'; this.button.title = '性能优化工具箱'; document.body.appendChild(this.button); this.panel = document.createElement('div'); this.panel.className = 'perfopt-ui-panel'; this.panel.innerHTML = `
性能优化工具箱
Core Web Vitals
FCP
-- 等待中
LCP
-- 等待中
CLS
-- 等待中
图片懒加载
${Config.lazyLoad.enabled ? '已启用' : '已禁用'}
GPU加速
${Config.hardwareAcceleration.enabled ? '已启用' : '已禁用'}
内容可见性优化
${Config.contentVisibility.enabled ? '已启用' : '已禁用'}
懒加载图片: 0
GPU加速元素: 0
视口内元素: 0
视口外隐藏: 0
DOM深度: 计算中...
网络类型: ${Env.networkType}
WebGPU支持: ${Env.features.webgpu ? '是' : '否'}
性能等级: ${Env.performanceTier === 2 ? '高性能' : Env.performanceTier === 1 ? '中等性能' : '低性能'}
版本: v3.7.1-compatibility-optimized
`; document.body.appendChild(this.panel); } createFallbackUI() { const style = document.createElement('style'); style.textContent = ` #perfopt-fallback-btn { position: fixed !important; bottom: 20px !important; right: 20px !important; padding: 10px 20px !important; background: #007bff !important; color: white !important; z-index: ${Config.ui.zIndex} !important; cursor: pointer !important; font-family: Arial, sans-serif !important; border-radius: 25px !important; font-size: 14px !important; box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2) !important; user-select: none !important; } `; document.head.appendChild(style); this.button = document.createElement('div'); this.button.id = 'perfopt-fallback-btn'; this.button.textContent = '⚡ 性能优化'; this.button.onclick = () => { const info = ` 性能优化工具已加载 版本: v3.7.1-compatibility-optimized 状态: 已运行 优化功能: ✅ 图片懒加载 ✅ GPU加速优化 (WebGPU兼容) ✅ 内容可见性优化 (视口感知) ✅ DOM深度分析 ✅ Core Web Vitals监控 环境信息: 设备性能: ${Env.performanceTier === 2 ? '高性能' : Env.performanceTier === 1 ? '中等性能' : '低性能'} 网络类型: ${Env.networkType} WebGPU支持: ${Env.features.webgpu ? '是' : '否'} `; alert(info); }; document.body.appendChild(this.button); Logger.warn('UIController', '使用降级UI'); } startAutoHideTimer() { this.autoHideTimeout = setTimeout(() => { if (!this.panelVisible && !this.isHovered) { this.hideButton(); } }, Config.ui.autoHideDelay); } resetAutoHideTimer() { if (this.autoHideTimeout) { clearTimeout(this.autoHideTimeout); } if (!this.panelVisible) { this.startAutoHideTimer(); } } showButton() { if (this.button) { this.button.classList.remove('hidden'); } } hideButton() { if (this.button) { this.button.classList.add('hidden'); } } attachEvents() { if (!this.button) return; this.button.addEventListener('click', () => { if (this.panel) { this.panelVisible = !this.panelVisible; this.panel.classList.toggle('visible'); if (this.panelVisible) { this.showButton(); this.updateStats(); this.scheduleStatsUpdate(); this.resetAutoHideTimer(); } else { this.isUpdateScheduled = false; this.startAutoHideTimer(); } } }); this.button.addEventListener('mouseenter', () => { this.isHovered = true; if (this.hoverTimeout) { clearTimeout(this.hoverTimeout); } this.showButton(); }); this.button.addEventListener('mouseleave', () => { this.isHovered = false; this.hoverTimeout = setTimeout(() => { if (!this.panelVisible) { this.hideButton(); } }, Config.ui.hoverDelay); }); if (this.panel) { const closeBtn = this.panel.querySelector('.perfopt-panel-close'); closeBtn.addEventListener('click', () => { this.panelVisible = false; this.panel.classList.remove('visible'); this.isUpdateScheduled = false; this.startAutoHideTimer(); }); this.panel.addEventListener('mouseenter', () => { this.isHovered = true; this.showButton(); }); this.panel.addEventListener('mouseleave', () => { this.isHovered = false; if (!this.panelVisible) { this.startAutoHideTimer(); } }); document.addEventListener('click', (e) => { if (!this.button.contains(e.target) && !this.panel.contains(e.target)) { this.panelVisible = false; this.panel.classList.remove('visible'); this.isUpdateScheduled = false; this.startAutoHideTimer(); } }); } window.addEventListener('scroll', () => { this.resetAutoHideTimer(); this.showButton(); }, { passive: true }); window.addEventListener('mousemove', () => { this.resetAutoHideTimer(); this.showButton(); }, { passive: true }); window.addEventListener('resize', () => { this.resetAutoHideTimer(); this.showButton(); }, { passive: true }); } destroy() { super.destroy(); this.isUpdateScheduled = false; if (this.autoHideTimeout) { clearTimeout(this.autoHideTimeout); this.autoHideTimeout = null; } if (this.hoverTimeout) { clearTimeout(this.hoverTimeout); this.hoverTimeout = null; } const style = document.getElementById('perfopt-ui-style'); if (style) style.remove(); if (this.button && document.body.contains(this.button)) { document.body.removeChild(this.button); } if (this.panel && document.body.contains(this.panel)) { document.body.removeChild(this.panel); } } } // ======================== // 9. 应用控制器 // ======================== class AppController extends BaseModule { constructor() { super('AppController'); this.modules = {}; } init() { super.init(); try { const hostname = window.location.hostname; if (Config.blacklistedDomains.some(domain => hostname.includes(domain))) { Logger.info('AppController', '当前域名在黑名单中,脚本终止运行'); return; } Logger.info('AppController', '开始初始化各模块'); // 初始化性能监控器(先于UI,确保数据可被获取) this.modules.performanceMonitor = new PerformanceMonitor(); this.modules.performanceMonitor.init(); // 初始化UI控制器并注入性能监控器引用 this.modules.uiController = new UIController(); this.modules.uiController.setPerformanceMonitor(this.modules.performanceMonitor); this.modules.uiController.init(); Logger.info('AppController', 'UI控制器初始化成功'); this.modules.imageOptimizer = new ImageOptimizer(); this.modules.imageOptimizer.init(); this.modules.gpuAccelerator = new GPUAccelerator(); this.modules.gpuAccelerator.init(); this.modules.contentVisibility = new ContentVisibility(); this.modules.contentVisibility.init(); this.modules.preconnectOptimizer = new PreconnectOptimizer(); this.modules.preconnectOptimizer.init(); Logger.info('AppController', '所有模块初始化完成'); window.addEventListener('beforeunload', () => this.destroy()); } catch (error) { Logger.error('AppController', `初始化失败: ${error.message}`); Logger.error('AppController', error.stack); this.destroy(); createEmergencyUI(); } } destroy() { Object.values(this.modules).reverse().forEach(module => { if (module && module.destroy) { try { module.destroy(); } catch (e) { Logger.warn('AppController', `模块${module.moduleName}销毁失败: ${e.message}`); } } }); super.destroy(); } } // ======================== // 10. 启动与错误处理 // ======================== function bootstrap() { try { Logger.info('Bootstrap', '性能优化工具加载中...'); const app = new AppController(); app.init(); window.PerfOptimizer = app; Logger.info('Bootstrap', '性能优化工具加载成功'); setTimeout(() => { Logger.info('Bootstrap', { uiController: !!window.PerfOptimizer?.modules?.uiController, button: !!document.querySelector('.perfopt-ui-button, #perfopt-fallback-btn'), panel: !!document.querySelector('.perfopt-ui-panel') }); }, 100); } catch (error) { Logger.error('Bootstrap', `加载失败: ${error.message}`); Logger.error('Bootstrap', error.stack); createEmergencyUI(); } } function createEmergencyUI() { const style = document.createElement('style'); style.textContent = ` #emergency-perf-btn { position: fixed !important; bottom: 20px !important; right: 20px !important; padding: 10px 20px !important; background: #dc3545 !important; color: white !important; z-index: 10000 !important; cursor: pointer !important; font-family: Arial, sans-serif !important; border-radius: 25px !important; font-size: 14px !important; box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2) !important; user-select: none !important; } `; document.head.appendChild(style); const button = document.createElement('div'); button.id = 'emergency-perf-btn'; button.textContent = '⚡ 修复失败'; button.onclick = () => { const info = ` 性能优化工具加载失败 错误信息: ${window.lastPerfError?.message || '未知错误'} 请尝试: 1. 刷新页面 2. 重新安装脚本 3. 检查浏览器控制台 如果问题持续,请报告bug。 `; alert(info); }; document.body.appendChild(button); } window.addEventListener('error', (e) => { window.lastPerfError = e; Logger.error('Global', e.message); }); if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', bootstrap); } else { bootstrap(); } window.PerfUtils = { getConfig: () => JSON.parse(JSON.stringify(Config)), getEnv: () => Env, utils: { isSameOrigin: (url) => { try { return new URL(url, window.location.href).origin === window.location.origin; } catch (e) { return false; } } } }; })();