Greasy Fork

Greasy Fork is available in English.

禁用电商平台图片缩放效果 (终极版)

精准禁用淘宝、天猫、1688、京东等平台的图片放大镜(jqzoom)效果,方便右键。采用多重防御策略,彻底解决问题。

当前为 2025-06-11 提交的版本,查看 最新版本

// ==UserScript==
// @name             禁用电商平台图片缩放效果 (终极版)
// @name:en          Disable E-commerce Image Zoom Effect (Ultimate)
// @namespace        http://greasyfork.icu/users/3001-hanjian-wu
// @version          1.6.0
// @description      精准禁用淘宝、天猫、1688、京东等平台的图片放大镜(jqzoom)效果,方便右键。采用多重防御策略,彻底解决问题。
// @description:en   Precisely disable image magnifier (jqzoom) on Taobao, Tmall, 1688, JD. Uses a multi-layered defense strategy for a complete fix.
// @author           hanjian wu (Enhanced by AI)
// @homepage         http://greasyfork.icu/users/3001-hanjian-wu
// @license          MIT
// @match            *://*.taobao.com/item.htm*
// @match            *://*.tmall.com/item.htm*
// @match            *://*.1688.com/offer/*.html*
// @match            *://item.taobao.com/*
// @match            *://detail.tmall.com/*
// @match            *://detail.1688.com/*
// @match            *://item.jd.com/*
// @match            *://*.jd.com/product/*
// @grant            none
// @run-at           document-start
// @noframes
// ==/UserScript==

(function() {
    'use strict';
    console.log('电商图片缩放禁用脚本 v1.6.0 (多重防御策略)');

    // --- 第一道防线:CSS 隐藏 ---
    // 尽早注入CSS,直接隐藏 jqzoom 创建的元素,这是最高效的方式。
    const style = document.createElement('style');
    style.id = 'disable-zoom-styles-ultimate';
    style.textContent = `
        /* 根据你捕获的HTML,精准隐藏jqzoom的动态元素 */
        .jqZoomPup,   /* 放大镜方块 */
        .zoomdiv,     /* 放大后图片的容器 */
        .jqzoom-window /* jqzoom可能的另一种容器类名 */
        {
            display: none !important;
            visibility: hidden !important;
            opacity: 0 !important;
            pointer-events: none !important;
            position: absolute !important;
            top: -99999px !important;
            left: -99999px !important;
        }

        /* 确保主图本身可交互 */
        #spec-n1, #spec-img {
             cursor: default !important;
        }
    `;
    (document.head || document.documentElement).appendChild(style);
    console.log('[防御1] CSS规则已注入,隐藏jqzoom动态元素。');


    // --- 第二道防线:重写 jQuery 插件 ---
    // 多数情况下,jqzoom是jQuery插件。我们在它执行前,把它定义为空函数。
    // 这需要持续检测 jQuery 是否已加载。
    function neutralizeJqzoomPlugin() {
        // 检查jQuery和jqzoom插件是否已存在于window对象
        if (typeof window.jQuery !== 'undefined' && typeof window.jQuery.fn.jqzoom !== 'undefined') {
            window.jQuery.fn.jqzoom = function() {
                console.log('[防御2] jqzoom() 已被禁用,调用无效。');
                return this; // 维持jQuery的链式调用
            };
            // 成功禁用后,可以停止定时器
            if (jqzoomCheckInterval) {
                clearInterval(jqzoomCheckInterval);
                console.log('[防御2] 成功禁用jqzoom插件,停止检测。');
            }
        }
    }

    // 因为不确定jQuery何时加载,所以设置一个定时器持续检查
    const jqzoomCheckInterval = setInterval(neutralizeJqzoomPlugin, 100);
    // 页面加载完成后,如果还没禁用,再尝试一次
    window.addEventListener('load', () => {
        neutralizeJqzoomPlugin();
        // 如果5秒后还没禁用成功,就不再浪费资源了
        setTimeout(() => clearInterval(jqzoomCheckInterval), 5000);
    });


    // --- 第三道防线:阻止事件传播 ---
    // 作为终极保险,直接在容器上捕获并阻止鼠标事件传播。
    function blockHoverEvents(container) {
        if (!container || container.dataset.eventsBlocked) return;

        const eventsToBlock = ['mouseenter', 'mouseover', 'mousemove'];
        eventsToBlock.forEach(eventType => {
            container.addEventListener(eventType, (e) => {
                e.stopImmediatePropagation(); // 阻止后续任何同类事件的监听器执行
            }, { capture: true }); // 使用捕获模式,确保我们的监听器最先执行
        });
        container.dataset.eventsBlocked = 'true';
        console.log(`[防御3] 已在元素 #${container.id} 上阻止鼠标悬停事件。`);
    }

    // --- 执行与监控 ---
    // 使用 MutationObserver 监控DOM变化,以应对异步加载的图片廊。
    const observer = new MutationObserver((mutations) => {
        for (const mutation of mutations) {
            for (const node of mutation.addedNodes) {
                if (node.nodeType === 1) { // 确保是元素节点
                    // 查找目标容器
                    const zoomContainer = node.matches('#spec-n1, .jqzoom') ? node : node.querySelector('#spec-n1, .jqzoom');
                    if (zoomContainer) {
                        blockHoverEvents(zoomContainer);
                        // 找到了就可以停止观察,或者根据需要继续
                        // observer.disconnect();
                    }
                }
            }
        }
    });

    // 等待DOM加载完成后开始观察
    document.addEventListener('DOMContentLoaded', () => {
        const initialContainer = document.querySelector('#spec-n1, .jqzoom');
        if (initialContainer) {
            blockHoverEvents(initialContainer);
        }

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

})();