WebP加载优化(此脚本转为图片加载而设计)

智能检测浏览器能力,优先使用原生懒加载和WebP,优雅降级方案

// ==UserScript==
// @name         WebP加载优化(此脚本转为图片加载而设计)
// @namespace    http://tampermonkey.net/
// @version      1.4
// @description  智能检测浏览器能力,优先使用原生懒加载和WebP,优雅降级方案
// @author       KiwiFruit
// @match        *://*/*
// @grant        none
// @license      MIT
// ==/UserScript==

(function() {
    'use strict';

    // 浏览器能力检测
    const supportsLazyLoading = 'loading' in HTMLImageElement.prototype;
    const supportsWebP = document.createElement('canvas').toDataURL('image/webp').indexOf('data:image/webp') === 0;

    // 配置参数
    const config = {
        rootMargin: '200px 0px', // 提前200px加载
        threshold: 0.01,
        retryLimit: 2,
        retryDelay: 3000,
        webpQuality: 75,
        placeholder: 'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMSIgaGVpZ2h0PSIxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNmMGYwZjAiLz48L3N2Zz4='
    };

    // 添加样式
    const style = document.createElement('style');
    style.textContent = `
        img[data-src], img[data-webp-src] {
            opacity: 0;
            transition: opacity 0.4s ease-in-out;
            background-color: #f5f5f5;
            background-image: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%);
            background-size: 200% 100%;
            animation: shimmer 1.5s infinite;
        }

        @keyframes shimmer {
            0% { background-position: 200% 0; }
            100% { background-position: -200% 0; }
        }

        img.loaded {
            opacity: 1;
            background: none;
        }

        img.error {
            opacity: 0.7;
            background: #ffebee;
            position: relative;
        }

        img.error::after {
            content: "图片加载失败";
            position: absolute;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            color: #d32f2f;
            font-size: 12px;
            background: rgba(255,255,255,0.8);
            padding: 2px 6px;
            border-radius: 3px;
        }
    `;
    document.head.appendChild(style);

    // 图片处理函数
    function processImage(img) {
        if (img.dataset.processed) return;

        // 设置占位符
        if (!img.src && !img.dataset.src) {
            img.src = config.placeholder;
        }

        // 原生懒加载处理
        if (supportsLazyLoading) {
            img.setAttribute('loading', 'lazy');

            // WebP处理
            if (supportsWebP && img.dataset.webpSrc) {
                img.src = img.dataset.webpSrc;
            } else if (img.dataset.src) {
                img.src = img.dataset.src;
            }

            img.onload = () => img.classList.add('loaded');
            img.onerror = () => handleImageError(img);
            img.dataset.processed = 'true';
            return;
        }

        // 非原生懒加载处理
        if (img.dataset.src || img.dataset.webpSrc) {
            img.removeAttribute('src');
            observer.observe(img);
        }
    }

    // 图片错误处理
    function handleImageError(img) {
        img.classList.add('error');
        const retryCount = parseInt(img.dataset.retryCount || '0');

        if (retryCount < config.retryLimit) {
            img.dataset.retryCount = retryCount + 1;
            setTimeout(() => {
                img.src = img.dataset.src || img.dataset.webpSrc || img.src;
            }, config.retryDelay);
        }
    }

    // IntersectionObserver回调
    function handleIntersection(entries) {
        entries.forEach(entry => {
            if (entry.isIntersecting) {
                const img = entry.target;
                observer.unobserve(img);

                // 设置图片源
                if (supportsWebP && img.dataset.webpSrc) {
                    img.src = img.dataset.webpSrc;
                } else if (img.dataset.src) {
                    img.src = img.dataset.src;
                }

                img.onload = () => img.classList.add('loaded');
                img.onerror = () => handleImageError(img);
                img.dataset.processed = 'true';
            }
        });
    }

    // 创建观察者
    const observer = new IntersectionObserver(handleIntersection, {
        rootMargin: config.rootMargin,
        threshold: config.threshold
    });

    // 处理现有图片
    document.querySelectorAll('img[data-src], img[data-webp-src]').forEach(processImage);

    // 监听动态添加的图片
    const mutationObserver = new MutationObserver(mutations => {
        mutations.forEach(mutation => {
            mutation.addedNodes.forEach(node => {
                if (node.nodeType === 1 && node.tagName === 'IMG') {
                    processImage(node);
                } else if (node.nodeType === 1) {
                    node.querySelectorAll('img[data-src], img[data-webpSrc]').forEach(processImage);
                }
            });
        });
    });

    mutationObserver.observe(document.body, {
        childList: true,
        subtree: true
    });

    // 性能监控
    if (window.performance && window.performance.mark) {
        window.performance.mark('lazyLoadStart');
        window.addEventListener('load', () => {
            window.performance.mark('lazyLoadEnd');
            window.performance.measure('lazyLoad', 'lazyLoadStart', 'lazyLoadEnd');
            const measures = window.performance.getEntriesByName('lazyLoad');
            if (measures.length > 0) {
                console.log(`[懒加载优化] 初始化耗时: ${measures[0].duration.toFixed(2)}ms`);
            }
        });
    }
})();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址