强力代理图片放大(支持鼠标滚轮缩放与拖动)

弹窗放大图片,支持鼠标滚轮缩放,拖动时点击不关闭弹窗

// ==UserScript==
// @license  paperfly
// @name         强力代理图片放大(支持鼠标滚轮缩放与拖动)
// @namespace    http://tampermonkey.net/
// @version      1.6
// @description  弹窗放大图片,支持鼠标滚轮缩放,拖动时点击不关闭弹窗
// @match        https://www.bilibili.com/video/*
// @grant        none
// ==/UserScript==

(function () {
  'use strict';

  function showPopup(src) {
    if (document.getElementById('img-popup-overlay')) return;

    const overlay = document.createElement('div');
    overlay.id = 'img-popup-overlay';
    overlay.isDragging = false; // 标记拖动状态
    Object.assign(overlay.style, {
      position: 'fixed',
      top: 0, left: 0,
      width: '100vw', height: '100vh',
      backgroundColor: 'rgba(0,0,0,0.85)',
      display: 'flex',
      justifyContent: 'center',
      alignItems: 'center',
      zIndex: 9999999,
      cursor: 'pointer',
      overflow: 'hidden',
    });

    const img = document.createElement('img');
    img.src = src.startsWith('//') ? 'https:' + src : src;
    Object.assign(img.style, {
      maxWidth: '90%',
      maxHeight: '90%',
      borderRadius: '8px',
      boxShadow: '0 0 20px white',
      userSelect: 'none',
      pointerEvents: 'auto',
      transformOrigin: 'center center',
      transition: 'transform 0.1s ease-out',
      cursor: 'grab',
    });

    let scale = 1;
    let isDragging = false;
    let dragStart = { x: 0, y: 0 };
    let imgPos = { x: 0, y: 0 };

    img.addEventListener('wheel', e => {
      e.preventDefault();
      const delta = e.deltaY < 0 ? 0.1 : -0.1;
      scale = Math.min(Math.max(0.5, scale + delta), 5);
      updateTransform();
    });

    img.addEventListener('mousedown', e => {
      e.preventDefault();
      isDragging = true;
      overlay.isDragging = true;
      dragStart.x = e.clientX - imgPos.x;
      dragStart.y = e.clientY - imgPos.y;
      img.style.cursor = 'grabbing';
    });

    img.addEventListener('mousemove', e => {
      if (!isDragging) return;
      e.preventDefault();
      imgPos.x = e.clientX - dragStart.x;
      imgPos.y = e.clientY - dragStart.y;
      updateTransform();
    });

    img.addEventListener('mouseup', e => {
      if (!isDragging) return;
      e.preventDefault();
      isDragging = false;
      overlay.isDragging = false;
      img.style.cursor = 'grab';
    });

    // 处理鼠标移出图片时,取消拖动状态,避免异常
    img.addEventListener('mouseleave', e => {
      if (!isDragging) return;
      e.preventDefault();
      isDragging = false;
      overlay.isDragging = false;
      img.style.cursor = 'grab';
    });

    // 点击图片阻止冒泡,避免关闭弹窗
    img.addEventListener('click', e => {
      e.stopPropagation();
    });

    // 点击遮罩层关闭弹窗,但拖动时不关闭
    overlay.addEventListener('click', () => {
      if (!overlay.isDragging) {
        overlay.remove();
      }
    });

    function updateTransform() {
      img.style.transform = `translate(${imgPos.x}px, ${imgPos.y}px) scale(${scale})`;
    }

    overlay.appendChild(img);
    document.body.appendChild(overlay);
  }

  function updateCursorStyle() {
    const imgs = document.querySelectorAll('img.img-preview');
    imgs.forEach(img => {
      img.style.cursor = 'zoom-in';
    });
  }

  document.body.addEventListener('click', (e) => {
    let target = e.target;
    while (target && target !== document.body) {
      if (target.tagName === 'IMG' && target.classList.contains('img-preview')) {
        showPopup(target.src);
        break;
      }
      target = target.parentElement;
    }
  }, true);

  window.addEventListener('load', () => {
    updateCursorStyle();
    const observer = new MutationObserver(() => {
      updateCursorStyle();
    });
    observer.observe(document.body, { childList: true, subtree: true });
  });
})();