图片预览 - Image Preview

按空格键预览图片,类似 macOS Quick Look

// ==UserScript==
// @name         图片预览 - Image Preview
// @namespace    http://tampermonkey.net/
// @version      1.0
// @description  按空格键预览图片,类似 macOS Quick Look
// @author       You
// @match        *://*/*
// @grant        none
// @run-at       document-end
// ==/UserScript==

(function() {
    'use strict';

    let isPreviewMode = false;
    let currentElement = null;
    let previewContainer = null;
    let previewContent = null;
    let loadingIndicator = null;

    // 创建预览容器
    function createPreviewContainer() {
        previewContainer = document.createElement('div');
        previewContainer.id = 'image-preview-container';
        previewContainer.style.cssText = `
            position: fixed;
            top: 0;
            left: 0;
            width: 100vw;
            height: 100vh;
            background: rgba(0, 0, 0, 0.9);
            z-index: 999999;
            display: none;
            justify-content: center;
            align-items: center;
            backdrop-filter: blur(10px);
            cursor: pointer;
        `;

        previewContent = document.createElement('div');
        previewContent.style.cssText = `
            max-width: 95vw;
            max-height: 90vh;
            position: relative;
            border-radius: 10px;
            overflow: hidden;
            box-shadow: 0 10px 50px rgba(0, 0, 0, 0.5);
            cursor: auto;
        `;

        loadingIndicator = document.createElement('div');
        loadingIndicator.innerHTML = '加载中...';
        loadingIndicator.style.cssText = `
            color: white;
            font-size: 18px;
            text-align: center;
            font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
        `;

        previewContainer.appendChild(previewContent);
        document.body.appendChild(previewContainer);

        // 点击背景关闭预览
        previewContainer.addEventListener('click', function(e) {
            if (e.target === previewContainer) {
                closePreview();
            }
        });
    }

    // 获取当前鼠标悬停的图片元素
    function getCurrentHoverImage() {
        const images = document.querySelectorAll('img');
        let hoveredImage = null;

        images.forEach(img => {
            if (img.matches(':hover')) {
                hoveredImage = img;
            }
        });

        // 如果没有悬停图片,尝试获取焦点图片
        if (!hoveredImage) {
            const focusedElement = document.activeElement;
            if (focusedElement && focusedElement.tagName === 'IMG') {
                hoveredImage = focusedElement;
            }
        }

        return hoveredImage;
    }

    // 预览图片
    function previewImage(src, alt = '') {
        const img = document.createElement('img');
        img.src = src;
        img.alt = alt;

        img.onload = function() {
            // 获取图片原始尺寸
            const originalWidth = img.naturalWidth;
            const originalHeight = img.naturalHeight;

            // 获取屏幕尺寸
            const screenWidth = window.innerWidth;
            const screenHeight = window.innerHeight;
            const maxWidth = screenWidth * 0.9;
            const maxHeight = screenHeight * 0.9;

            // 计算智能缩放比例
            let scale = 1;
            const minDimension = Math.min(originalWidth, originalHeight);

            if (minDimension < 200) {
                // 小图片:放大3-5倍
                scale = Math.min(5, Math.max(3, 800 / minDimension));
            } else if (minDimension < 400) {
                // 中等图片:放大1.5-3倍
                scale = Math.min(3, Math.max(1.5, 600 / minDimension));
            } else if (minDimension < 800) {
                // 较大图片:放大1-2倍
                scale = Math.min(2, Math.max(1, 800 / minDimension));
            } else {
                // 大图片:按需缩小或保持原大小
                scale = Math.min(1, Math.min(maxWidth / originalWidth, maxHeight / originalHeight));
            }

            const targetWidth = Math.min(originalWidth * scale, maxWidth);
            const targetHeight = Math.min(originalHeight * scale, maxHeight);

            img.style.cssText = `
                width: ${targetWidth}px;
                height: ${targetHeight}px;
                object-fit: contain;
                border-radius: 10px;
                max-width: 90vw;
                max-height: 90vh;
            `;

            previewContent.innerHTML = '';
            previewContent.appendChild(img);
        };

        img.onerror = function() {
            previewContent.innerHTML = '<div style="color: white; padding: 20px; text-align: center;">图片加载失败</div>';
        };

        previewContent.appendChild(loadingIndicator);
    }

    // 显示预览
    function showPreview() {
        if (!previewContainer) {
            createPreviewContainer();
        }

        previewContainer.style.display = 'flex';
        document.body.style.overflow = 'hidden';
        isPreviewMode = true;
    }

    // 关闭预览
    function closePreview() {
        if (previewContainer) {
            // 清空预览内容
            if (previewContent) {
                previewContent.innerHTML = '';
            }

            previewContainer.style.display = 'none';
        }
        document.body.style.overflow = '';
        isPreviewMode = false;
        currentElement = null;

        // 强制垃圾回收(如果浏览器支持)
        if (window.gc) {
            window.gc();
        }
    }

    // 处理图片预览
    function handleImagePreview(img) {
        currentElement = img;
        showPreview();
        previewImage(img.src, img.alt);
    }

    // 键盘事件处理
    document.addEventListener('keydown', function(e) {
        // 屏蔽空格键的默认行为(翻页)
        if (e.code === 'Space') {
            // 如果当前在输入框中,不拦截
            const activeElement = document.activeElement;
            const isInputField = activeElement && (
                activeElement.tagName === 'INPUT' ||
                activeElement.tagName === 'TEXTAREA' ||
                activeElement.contentEditable === 'true'
            );

            if (isInputField) {
                return;
            }

            e.preventDefault();

            if (isPreviewMode) {
                closePreview();
            } else {
                const img = getCurrentHoverImage();
                if (img && img.tagName === 'IMG') {
                    handleImagePreview(img);
                }
            }
        }

        // ESC键关闭预览
        if (e.key === 'Escape' && isPreviewMode) {
            closePreview();
        }
    });

    // 鼠标移动时更新当前图片
    document.addEventListener('mousemove', function(e) {
        if (isPreviewMode) return;

        const element = e.target;
        if (element && element.tagName === 'IMG') {
            // 添加视觉提示
            element.style.outline = '2px solid rgba(0, 122, 255, 0.5)';
            element.style.outlineOffset = '2px';

            // 清除其他图片的提示
            document.querySelectorAll('img').forEach(img => {
                if (img !== element) {
                    img.style.outline = '';
                    img.style.outlineOffset = '';
                }
            });
        } else {
            // 清除所有提示
            document.querySelectorAll('img').forEach(img => {
                img.style.outline = '';
                img.style.outlineOffset = '';
            });
        }
    });

    console.log('图片预览脚本已加载');
})();