您需要先安装一个扩展,例如 篡改猴、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();
- }
- })();