您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Basic userscript implementation of the Imagus Hoverzoom extension
// ==UserScript== // @name Hover Zoom Revamped // @namespace http://tampermonkey.net/ // @version 0.2 // @description Basic userscript implementation of the Imagus Hoverzoom extension // @author TetteDev // @match *://*/* // @icon data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw== // @license MIT // @run-at document-start // @noframes // ==/UserScript== const HoverImageId = `hover_image_${makeid(6)}`; const HoverAttribute = "data-hoverable"; const NodeIsImage = (node) => { return node.tagName === "IMG" || node.nodeName === "IMG"; }; let mouseX = 0; let mouseClientX = 0; let mouseY = 0; let mouseClientY = 0; let renderAtMousePosition = false; if (renderAtMousePosition) { const fnUpdateMousePosition = (e) => { mouseX = e.pageX; mouseClientX = e.clientX; mouseY = e.pageY; mouseClientY = e.clientY; }; document.addEventListener('mousemove', fnUpdateMousePosition, false); }; function containsImageDimensions(url) { const dimensionRegex = /(\d{2,4})x(\d{2,4})/; const match = url.match(dimensionRegex); if (match) { const width = parseInt(match[1], 10); const height = parseInt(match[2], 10); if (width > 0 && height > 0 && width <= 10000 && height <= 10000) { return { width: width, height: height }; } } return null; } function isLazyLoaded(imgElement) { if (!imgElement || imgElement.tagName.toLowerCase() !== 'img') { return false; } if (imgElement.hasAttribute('loading') && imgElement.getAttribute('loading') === 'lazy') { return true; } const lazyAttributes = ['data-src', 'data-lazy-src', 'data-srcset']; if (lazyAttributes.some((attr) => imgElement.hasAttribute(attr))) { return true; } const possibleIndicatorsClassnameLazy = ["lazy", "lazyloaded"]; if (possibleIndicatorsClassnameLazy.some((lazy) => imgElement.className.includes(lazy))) { return true; } // check if src might contain 'lazy' or 'lazyloaded' return false; } function makeid(length, allowedCharacters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz') { let result = ''; const characters = allowedCharacters || 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'; const charactersLength = characters.length; let counter = 0; while (counter < length) { result += characters.charAt(Math.floor(Math.random() * charactersLength)); counter += 1; } return result; } (function() { 'use strict'; const fnTryQuerySelector = (node, selector, all = false) => { if (!node) return []; if (!selector) return []; try { return all ? node.querySelectorAll(selector) : node.querySelector(selector); } catch (err) { return []; } }; const fnTryHasAttribute = (node, attributeName) => { if(typeof node === 'object' && node !== null && 'getAttribute' in node && node.hasAttribute(attributeName)) return true; else return false; }; window.addEventListener('load', function () { document.querySelectorAll("img").forEach((node) => { const isImageOrContainsImage = NodeIsImage(node) || (fnTryQuerySelector(node, "img", true).length > 0); if (isImageOrContainsImage) { if (fnTryHasAttribute(node, HoverAttribute)) return; node.setAttribute(HoverAttribute, "true"); node.addEventListener("mouseenter", OnElementMouseEnter); node.addEventListener("mouseleave", OnElementMouseLeave); } }); new MutationObserver((mutationRecords, observer) => { mutationRecords.forEach((mutation) => { const addedNodes = mutation.addedNodes; if (addedNodes.length == 0) return; addedNodes.forEach((node) => { if (node.id === HoverImageId) return; if (fnTryHasAttribute(node, HoverAttribute)) return; const isImageOrContainsImage = NodeIsImage(node) || (fnTryQuerySelector(node, "img", true).length > 0); // TODO: if NodeIsImage(node) returned false but isImageOrContainsImage is still true // determine if its worth making it hoverable by checking the child "img" tags in that // element and confirming they meet some kind of requirements, such as // bigger than some size, child images count is only 1 etc etc if (isImageOrContainsImage) { node.setAttribute(HoverAttribute, "true"); node.addEventListener("mouseenter", OnElementMouseEnter); node.addEventListener("mouseleave", OnElementMouseLeave); } }); }); }).observe(document, { attributes: false, childList: true, characterData: false, subtree: true }); }); function OnElementMouseEnter(event) { OnElementMouseLeave(null); const targetImage = NodeIsImage(event.currentTarget) ? event.currentTarget : event.currentTarget.querySelector("img"); let targetImageSource = ""; if (isLazyLoaded(targetImage)) { let dataSetUrls = targetImage.hasAttribute("data-srcset") ? targetImage.getAttribute("data-srcset").split(',').map((url) => url.trim().split(' ')[0]) : []; if (dataSetUrls) { targetImageSource = dataSetUrls.pop(); } else { targetImageSource = targetImage.getAttribute("data-src"); } } else { targetImageSource = targetImage.src; } if (!targetImageSource) { targetImageSource = targetImage.getAttribute("data-src") || targetImage.src || null; if (!targetImageSource) { event.currentTarget.removeEventListener("mouseenter", OnElementMouseEnter); event.currentTarget.removeEventListener("mouseleave", OnElementMouseLeave); return; } } let isBase64 = targetImageSource.includes("base64"); let width = "auto"; let height = "auto"; let urlDerivedImageDimensions = isBase64 ? null : containsImageDimensions(targetImageSource); if (urlDerivedImageDimensions) { width = `${urlDerivedImageDimensions.width}px`; height = `${urlDerivedImageDimensions.height}px`; } else { let hasWidthAttribute = targetImage.hasAttribute("width"); if (hasWidthAttribute) width = `${targetImage.getAttribute("width")}px`; let hasHeightAttribute = targetImage.hasAttribute("height"); if (hasHeightAttribute) height = `${targetImage.getAttribute("height")}px`; } // Default: render it at the center of the page let renderPositionX = "50%"; let renderPositionY = "50%"; if (renderAtMousePosition) { // Render at mouse renderPositionX = `${(mouseX)}px`; renderPositionY = `${(mouseY)}px`; // Render at mouse with some offset /* const imageWidth = parseInt(width); const imageHeight = parseInt(height); renderPositionX = (mouseClientX + (imageWidth / 2)); if (renderPositionX + imageWidth > window.innerWidth) { renderPositionX = window.innerWidth - imageWidth; } renderPositionY = (mouseClientY + (imageHeight / 2)); if (renderPositionY + imageHeight > window.innerHeight) { renderPositionY = window.innerHeight - imageHeight; } renderPositionX = `${renderPositionY}px`; renderPositionY = `${renderPositionY}px`; */ // Render at mouse but use percentages relative to the page view /* const xOffsetPercentage = 20; const yOffsetPercentage = 25; const xPositionPercentage = ((mouseX/window.innerWidth)*100) + xOffsetPercentage; const yPositionPercentage = ((mouseY/window.innerHeight)*100) + yOffsetPercentage; renderPositionX = `${xPositionPercentage}%`; renderPositionY = `${yPositionPercentage}%`; */ } const hover = document.createElement("img"); hover.src = targetImageSource; hover.id = HoverImageId; hover.style.cssText = ` margin: 0 auto; position: ${(renderAtMousePosition ? 'absolute' : 'fixed')}; left: ${renderPositionX} !important; top: ${renderPositionY} !important; transform: translate(-50%, -50%); width: ${width} !important; height: ${height} !important; z-index: 9999; border: 1px dashed red;`; document.body.appendChild(hover); } function OnElementMouseLeave(event) { let hover = document.querySelector(`#${HoverImageId}`); if (hover) hover.remove(); } })();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址