// ==UserScript== // @name Native Image Toggler // @namespace http://tampermonkey.net/ // @version 0.8 // @description 通过原生 UI 控制当前页面图片的显示和隐藏,支持持久化设置 // @author You // @match *://*/* // @grant GM_setValue // @grant GM_getValue // @grant GM_registerMenuCommand // @grant GM_addStyle // @run-at document-start // @downloadURL none // ==/UserScript== (function() { 'use strict'; // 配置常量 const STORAGE_KEY_PREFIX = 'img_toggle_'; const STYLE_ID = 'native-image-toggler-style'; const POSITION_KEY = 'img_toggle_position_'; const UI_VISIBLE_KEY = 'img_toggle_ui_visible_'; const DEFAULT_POSITION = { top: 10, right: 20 }; // 获取当前域名的设置键 const hostname = window.location.hostname; const storageKey = STORAGE_KEY_PREFIX + hostname; const positionKey = POSITION_KEY + hostname; // 状态:true 表示图片显示(默认),false 表示图片隐藏 // 默认所有网站都是显示的,除非用户手动关闭 let isImagesVisible = GM_getValue(storageKey, true); let uiPosition = GM_getValue(positionKey, DEFAULT_POSITION); let isUIVisible = GM_getValue(UI_VISIBLE_KEY + hostname, true); let isUIInitialized = false; // 防止重复初始化 UI // CSS 样式:隐藏图片的样式 const hideImageCSS = ` img, image, picture, svg, canvas, video, iframe { opacity: 0 !important; visibility: hidden !important; pointer-events: none !important; } * { background-image: none !important; } /* 排除我们自己的 UI */ #image-toggler-ui, #image-toggler-ui * { opacity: 1 !important; visibility: visible !important; pointer-events: auto !important; background-image: initial !important; } `; // CSS 样式:UI 控件的样式 - Windows 11 Fluent Design 风格 const uiCSS = ` #image-toggler-ui { position: fixed; z-index: 2147483647; font-family: "Segoe UI Variable", "Segoe UI", system-ui, sans-serif; background-color: #f3f3f3; color: #1a1a1a; padding: 5px 12px; border-radius: 4px; cursor: grab; user-select: none; border: 1px solid rgba(0,0,0,0.08); transition: background-color 0.1s ease, box-shadow 0.15s ease, opacity 0.2s ease; font-size: 12px; font-weight: 400; display: flex; align-items: center; gap: 5px; opacity: 0.95; white-space: nowrap; } #image-toggler-ui:hover { background-color: #e5e5e5; box-shadow: 0 2px 6px rgba(0,0,0,0.06); } #image-toggler-ui:active { background-color: #dcdcdc; } #image-toggler-ui.dragging { cursor: grabbing; transform: scale(1.02); box-shadow: 0 4px 12px rgba(0,0,0,0.12); } #image-toggler-icon svg { width: 14px; height: 14px; flex-shrink: 0; } #image-toggler-text { line-height: 1; } /* 切换动画 - 轻微闪烁 */ @keyframes img-toggle-flash { 0% { opacity: 1; } 50% { opacity: 0.6; } 100% { opacity: 1; } } #image-toggler-ui.toggle-animate { animation: img-toggle-flash 0.2s ease; } /* 暗色模式适配 */ @media (prefers-color-scheme: dark) { #image-toggler-ui { background-color: #323232; color: #fff; border-color: rgba(255,255,255,0.08); } #image-toggler-ui:hover { background-color: #454545; box-shadow: 0 2px 6px rgba(0,0,0,0.25); } #image-toggler-ui:active { background-color: #505050; } } `; // 初始化 function init() { // 尽早应用状态(如果需要隐藏图片) applyState(); // 等待 body 加载完成后创建 UI if (document.body) { setupUI(); applyUIState(); } else { document.addEventListener('DOMContentLoaded', setupUI); document.addEventListener('DOMContentLoaded', applyUIState); } // 注册菜单命令作为备用 GM_registerMenuCommand("切换图片显示/隐藏", toggleImages); GM_registerMenuCommand("切换控件显示/隐藏", toggleUIVisibility); // 添加键盘快捷键 Ctrl+Shift+I document.addEventListener('keydown', function(e) { if (e.ctrlKey && e.shiftKey && e.key === 'I') { e.preventDefault(); toggleImages(); } }); } function setupUI() { // 只在顶层窗口创建 UI,避免在 iframe 中重复创建 if (window.self !== window.top) return; // 防止重复创建 if (isUIInitialized) return; if (document.getElementById('image-toggler-ui')) { isUIInitialized = true; return; } // 添加 UI 样式 GM_addStyle(uiCSS); // 创建 UI createUI(); isUIInitialized = true; } // 创建 UI 控件 function createUI() { const div = document.createElement('div'); div.id = 'image-toggler-ui'; div.style.top = uiPosition.top + 'px'; div.style.right = uiPosition.right + 'px'; let isDragging = false; let hasDragged = false; // 用于标记是否真正发生了拖动 let dragOffsetX = 0; let dragOffsetY = 0; div.addEventListener('mousedown', function(e) { if (e.button !== 0) return; const rect = div.getBoundingClientRect(); dragOffsetX = e.clientX - rect.left; dragOffsetY = e.clientY - rect.top; isDragging = true; hasDragged = false; // 重置拖动标记 e.preventDefault(); }); document.addEventListener('mousemove', function(e) { if (!isDragging) return; // 检测是否发生了实际移动 if (!hasDragged) { hasDragged = true; div.classList.add('dragging'); } const newLeft = e.clientX - dragOffsetX; const newTop = e.clientY - dragOffsetY; div.style.right = 'auto'; div.style.left = newLeft + 'px'; div.style.top = newTop + 'px'; }); document.addEventListener('mouseup', function() { if (!isDragging) return; isDragging = false; div.classList.remove('dragging'); // 只在真正发生过拖动时才保存新位置 if (hasDragged) { const rect = div.getBoundingClientRect(); uiPosition = { top: rect.top, right: window.innerWidth - rect.left - rect.width }; GM_setValue(positionKey, uiPosition); div.style.left = 'auto'; div.style.right = uiPosition.right + 'px'; } // 延迟重置 hasDragged setTimeout(() => { hasDragged = false; }, 10); }); div.addEventListener('click', function(e) { // 如果发生过拖动,不触发切换 if (hasDragged) { e.preventDefault(); e.stopPropagation(); return; } toggleImages(); }); div.title = '拖动调整位置 | 点击切换图片显隐 | Ctrl+Shift+I 快捷键切换'; document.body.appendChild(div); updateUI(div); // 创建右上角 UI } // 更新 UI 显示 function updateUI(element) { const el = element || document.getElementById('image-toggler-ui'); if (!el) return; el.classList.remove('visible-mode', 'hidden-mode'); // 眼睛图标 SVG(显示状态) const eyeIconSVG = ``; // 隐藏眼睛图标 SVG(隐藏状态) const eyeOffIconSVG = ``; if (isImagesVisible) { el.innerHTML = `${eyeIconSVG}`; el.title = '当前:图片显示。点击隐藏图片'; } else { el.innerHTML = `${eyeOffIconSVG}`; el.title = '当前:图片隐藏。点击显示图片'; } // 切换动画 el.classList.remove('toggle-animate'); void el.offsetWidth; el.classList.add('toggle-animate'); } // 切换状态 function toggleImages() { isImagesVisible = !isImagesVisible; GM_setValue(storageKey, isImagesVisible); applyState(); updateUI(); } // 切换 UI 可见性 function toggleUIVisibility() { isUIVisible = !isUIVisible; GM_setValue(UI_VISIBLE_KEY, isUIVisible); applyUIState(); } // 应用 UI 可见性状态 function applyUIState() { const ui = document.getElementById('image-toggler-ui'); if (ui) { ui.style.display = isUIVisible ? 'flex' : 'none'; } } // 应用状态(添加或移除 CSS) function applyState() { let styleEl = document.getElementById(STYLE_ID); // 确保 head 存在,通常在 document-start 时 head 也是存在的(除了极早的情况) // 如果 head 不存在,稍微延时重试 if (!document.head) { setTimeout(applyState, 10); return; } if (!isImagesVisible) { // 如果需要隐藏图片,且样式元素不存在,则添加 if (!styleEl) { styleEl = document.createElement('style'); styleEl.id = STYLE_ID; styleEl.textContent = hideImageCSS; document.head.appendChild(styleEl); } } else { // 如果需要显示图片,且样式元素存在,则移除 if (styleEl) { styleEl.remove(); } } } // 启动 init(); })();