Webp图片加载优化

Optimize image loading by adding lazy loading, WebP support, and concurrent requests.

// ==UserScript==
// @name         Webp图片加载优化
// @namespace    http://tampermonkey.net/
// @version      1.0
// @description  Optimize image loading by adding lazy loading, WebP support, and concurrent requests.
// @author       KiwiFruit
// @match        *://*/*
// @grant        none
// @license MIT
// ==/UserScript==
(function() {
    'use strict';

    // 检查浏览器是否支持WebP
    function supportsWebP(callback) {
        const webP = new Image();
        webP.src = 'data:image/webp;base64,UklGRi4AAABXRUJQVlA4TCEAAAAvAUAAEB8wAiMwMAAgH8JeYW5kZXI=';
        webP.onload = webP.onerror = function () {
            callback(webP.height === 2);
        };
    }

    // 动态替换为WebP图片(如果有)
    function replaceWithWebP(imageElement, src) {
        const webPSrc = src.replace(/\.(jpg|jpeg|png)$/, '.webp');
        const img = new Image();
        img.src = webPSrc;
        img.onload = function() {
            imageElement.src = webPSrc;
        };
        img.onerror = function() {
            imageElement.src = src;
            console.log(`WebP version not found for ${src}, using original.`);
        };
    }

    // 并发加载图片
    function loadImages(imageUrls) {
        return Promise.all(imageUrls.map(url => {
            return new Promise((resolve, reject) => {
                const img = new Image();
                img.src = url;
                img.onload = resolve;
                img.onerror = reject;
            });
        }));
    }

    // 使用IntersectionObserver动态加载图片
    function setupDynamicLoading(images) {
        const viewportHeight = window.innerHeight;
        const rootMarginBottom = `${viewportHeight / 2}px`; // 设置rootMargin为视口高度的50%

        const observer = new IntersectionObserver((entries, observer) => {
            entries.forEach(entry => {
                if (entry.isIntersecting) {
                    const img = entry.target;
                    const src = img.getAttribute('data-src');
                    if (src) {
                        supportsWebP((isSupported) => {
                            if (isSupported) {
                                replaceWithWebP(img, src);
                            } else {
                                img.src = src;
                            }
                        });
                        observer.unobserve(img); // 停止观察已加载的图片
                    }
                }
            });
        }, { root: null, rootMargin: `0px 0px ${rootMarginBottom} 0px` }); // 只增加底部的rootMargin

        images.forEach(img => {
            if (!img.getAttribute('data-src')) {
                img.setAttribute('data-src', img.src);
                img.src = ''; // 清空src以防止立即加载
            }
            observer.observe(img);
        });
    }

    // 预加载首屏图片
    function preloadFirstScreenImages(images) {
        const viewportHeight = window.innerHeight;
        const firstScreenImages = Array.from(images).filter(img => {
            const rect = img.getBoundingClientRect();
            return rect.top <= viewportHeight && rect.bottom >= 0;
        }).map(img => img.getAttribute('data-src'));

        if (firstScreenImages.length > 0) {
            loadImages(firstScreenImages).then(() => {
                console.log('首屏图片已预加载');
            }).catch(error => {
                console.error('首屏图片预加载失败:', error);
            });
        }
    }

    // 确保DOM完全加载后再执行动态加载和首屏图片预加载
    window.addEventListener('load', () => {
        const images = document.querySelectorAll('img');
        preloadFirstScreenImages(images); // 首屏图片预加载
        setupDynamicLoading(images); // 动态加载所有图片
    });

    // 监听DOM变化,确保动态加载的内容也能被优化
    const mutationObserver = new MutationObserver(mutations => {
        mutations.forEach(mutation => {
            mutation.addedNodes.forEach(node => {
                if (node.nodeType === 1) {
                    const images = node.querySelectorAll('img');
                    if (images.length > 0) {
                        preloadFirstScreenImages(images); // 对新添加的图片进行首屏预加载
                        setupDynamicLoading(images); // 对新添加的图片进行动态加载
                    }
                }
            });
        });
    });
    mutationObserver.observe(document.body, { childList: true, subtree: true });
})();