// ==UserScript==
// @name 更好用的脚本!控制页面的图片显示与隐藏
// @version 6.2
// @description 稳定版图片隐藏/显示工具,解决错位问题,确保所有图片显示控制按钮,图片消失时自动清理控制元素
// @author hulada
// @match *://*/*
// @grant none
// @license MIT
// @run-at document-body
// @namespace https://greasyfork.org/users/1043548
// ==/UserScript==
(function () {
let active = false;
let currentX, currentY, initialX, initialY, xOffset = 0, yOffset = 0, startTime = 0;
window.imgHidenSet = null;
window.imgShownSet = null;
let yanEmoji = ["(‐^▽^‐)"];
let randomNumSet;
// 存储所有图片元素及其对应的控制按钮和轮廓
let imageControls = new Map();
let imageOutlines = new Map();
let mouseTimers = new Map();
// 自动隐藏延迟时间(毫秒)
const AUTO_HIDE_DELAY = 500;
// 简单的节流函数
function throttle(func, delay) {
let timeout;
return function(...args) {
if (!timeout) {
timeout = setTimeout(() => {
func.apply(this, args);
timeout = null;
}, delay);
}
};
}
let toggleSingleImage = function(img, button, outline) {
if (img.style.visibility === 'hidden' || img.style.visibility === '') {
img.style.visibility = 'visible';
img.style.transition = 'filter 0.6s ease';
img.style.filter = 'none';
outline.style.display = 'none';
button.innerText = '隐';
button.title = '点击隐藏图片';
} else {
img.style.visibility = 'hidden';
img.style.transition = 'filter 0.6s ease';
img.style.filter = 'blur(14px)';
outline.style.display = 'block';
button.innerText = '显';
button.title = '点击显示图片';
}
};
let startAutoHideTimer = function(button, outline) {
clearAutoHideTimer(button);
mouseTimers.set(button, setTimeout(() => {
button.style.opacity = '0.35';
outline.style.opacity = '0.35';
}, AUTO_HIDE_DELAY));
};
let clearAutoHideTimer = function(button) {
if (mouseTimers.has(button)) {
clearTimeout(mouseTimers.get(button));
mouseTimers.delete(button);
}
};
let createImageOutline = function(img) {
if (imageOutlines.has(img)) return imageOutlines.get(img);
let outline = document.createElement('div');
outline.style.position = 'absolute';
outline.style.zIndex = '999998';
outline.style.border = '2px dashed rgba(128, 128, 128, 0.6)';
outline.style.pointerEvents = 'none';
outline.style.transition = 'opacity 0.3s ease';
outline.style.display = 'none';
document.body.appendChild(outline);
imageOutlines.set(img, outline);
return outline;
};
// 清理已消失的图片控制元素
let cleanupOrphanedControls = function() {
const controlsToRemove = [];
const outlinesToRemove = [];
// 检查每个图片是否仍然存在且可见
imageControls.forEach((button, img) => {
if (!img || !img.isConnected || img.offsetWidth === 0 || img.offsetHeight === 0) {
controlsToRemove.push(img);
}
});
// 清理孤立的控制元素
controlsToRemove.forEach(img => {
const button = imageControls.get(img);
const outline = imageOutlines.get(img);
if (button) {
// 清理定时器
clearAutoHideTimer(button);
// 移除DOM元素
if (button.parentNode) {
button.parentNode.removeChild(button);
}
imageControls.delete(img);
}
if (outline) {
if (outline.parentNode) {
outline.parentNode.removeChild(outline);
}
imageOutlines.delete(img);
}
});
};
// 简化的位置更新(包含清理功能)
let updatePositions = throttle(function() {
// 先清理孤立的控制元素
cleanupOrphanedControls();
imageControls.forEach((button, img) => {
if (!img || !img.isConnected) return;
const rect = img.getBoundingClientRect();
const scrollX = window.pageXOffset || document.documentElement.scrollLeft;
const scrollY = window.pageYOffset || document.documentElement.scrollTop;
// 检查图片是否仍然可见
if (rect.width === 0 || rect.height === 0 || img.offsetWidth === 0 || img.offsetHeight === 0) {
return;
}
// 更新按钮位置
button.style.left = (rect.left + scrollX + 8) + 'px';
button.style.top = (rect.top + scrollY + 8) + 'px';
// 更新轮廓位置
const outline = imageOutlines.get(img);
if (outline) {
outline.style.left = (rect.left + scrollX - 3) + 'px';
outline.style.top = (rect.top + scrollY - 3) + 'px';
outline.style.width = (rect.width + 4) + 'px';
outline.style.height = (rect.height + 4) + 'px';
}
});
}, 200);
let createImageControlButton = function(img) {
if (imageControls.has(img)) return;
let button = document.createElement('div');
button.innerText = '显';
button.title = '点击隐藏图片';
let outline = createImageOutline(img);
// 样式设置
button.style.position = 'absolute';
button.style.zIndex = '999999';
button.style.padding = '4px 8px';
button.style.background = 'rgba(96, 96, 96, 0.8)';
button.style.border = '1px solid rgba(128, 128, 128, 0.9)';
button.style.color = 'rgba(240, 240, 240, 1)';
button.style.fontSize = '12px';
button.style.fontFamily = 'Arial, sans-serif';
button.style.lineHeight = '1.2';
button.style.textAlign = 'center';
button.style.cursor = 'pointer';
button.style.borderRadius = '4px';
button.style.transition = 'opacity 0.3s ease';
button.style.userSelect = 'none';
// 初始位置
updatePositions();
// 事件处理
button.addEventListener('mouseenter', function() {
clearAutoHideTimer(button);
button.style.opacity = '1';
button.style.background = 'rgba(128, 128, 128, 0.9)';
outline.style.opacity = '1';
});
button.addEventListener('mouseleave', function() {
startAutoHideTimer(button, outline);
button.style.background = 'rgba(96, 96, 96, 0.8)';
outline.style.opacity = '0.3';
});
button.addEventListener('click', function(e) {
e.preventDefault();
e.stopPropagation();
toggleSingleImage(img, button, outline);
clearAutoHideTimer(button);
button.style.opacity = '1';
});
document.body.appendChild(button);
imageControls.set(img, button);
// 初始状态
if (img.style.visibility !== 'hidden') {
img.style.visibility = 'hidden';
img.style.transition = 'filter 0.6s ease';
img.style.filter = 'blur(14px)';
outline.style.display = 'block';
}
startAutoHideTimer(button, outline);
};
// 查找所有图片
let findAllImages = function() {
let images = [];
// 标准图片
document.querySelectorAll('img').forEach(img => {
if (!imageControls.has(img) && img.offsetWidth > 0 && img.offsetHeight > 0) {
images.push(img);
}
});
return images;
};
let imgHiden = function() {
const images = findAllImages();
images.forEach(img => {
createImageControlButton(img);
});
// 更新所有位置并清理孤立的控制元素
updatePositions();
};
let imgShown = function() {
imageControls.forEach((button, img) => {
img.style.visibility = 'visible';
img.style.filter = 'none';
if (button.parentNode) {
button.parentNode.removeChild(button);
}
});
imageOutlines.forEach((outline) => {
if (outline.parentNode) {
outline.parentNode.removeChild(outline);
}
});
mouseTimers.forEach(timer => clearTimeout(timer));
mouseTimers.clear();
imageControls.clear();
imageOutlines.clear();
};
// 启动位置更新监听
let startPositionUpdates = function() {
// 监听滚动
window.addEventListener('scroll', updatePositions, { passive: true });
// 监听窗口大小变化
window.addEventListener('resize', updatePositions, { passive: true });
// 监听图片加载
document.addEventListener('load', function(e) {
if (e.target.tagName === 'IMG') {
setTimeout(updatePositions, 100);
}
}, true);
};
let handleButtonClick = function() {
if (window.imgHidenSet === null) {
clearInterval(window.imgShownSet);
window.imgShownSet = null;
startPositionUpdates();
imgHiden();
saveStorageList();
window.imgHidenSet = setInterval(imgHiden, 500);
} else {
clearInterval(window.imgHidenSet);
window.imgHidenSet = null;
imgShown();
deleteStorageList();
window.imgShownSet = setInterval(imgShown, 500);
}
};
let noDetectStorageList = function() {
if (localStorage.getItem('nopicValueList') !== null) {
let valueList = localStorage.getItem('nopicValueList').split(',');
if (valueList.indexOf(location.host) === -1) return true;
} else {
localStorage.setItem('nopicValueList', ['fxalll']);
return true;
}
return false;
};
let saveStorageList = function() {
if (noDetectStorageList()) {
let valueList = localStorage.getItem('nopicValueList').split(',');
if (!valueList.includes(location.host)) {
valueList.push(location.host);
localStorage.setItem('nopicValueList', valueList);
}
}
};
let deleteStorageList = function() {
if (!noDetectStorageList()) {
let valueList = localStorage.getItem('nopicValueList').split(',');
valueList = valueList.filter(value => value !== location.host);
localStorage.setItem('nopicValueList', valueList);
}
};
// 初始化
if (!noDetectStorageList()) {
startPositionUpdates();
imgHiden();
window.imgHidenSet = setInterval(imgHiden, 500);
}
let button = document.createElement('div');
button.innerText = "◀";
button.setAttribute("id", "myButton");
button.style.color = "#555";
button.style.padding = "10px 15px";
button.style.position = "fixed";
button.style.top = "50%";
button.style.left = "3px";
button.style.textAlign = "center";
button.style.alignContent = "center";
button.style.background = "rgba(128, 128, 128, 0.4)";
button.style.borderRadius = "15px";
button.style.border = "2px solid rgba(128, 128, 128, 0.7)";
button.style.cursor = "pointer";
button.style.transform = "translate3d(30%,0,0)";
button.style.transition = "all 0.1s ease, backdrop-filter 0.4s ease, background 0.4s ease, box-shadow 0.4s ease, opacity 0.4s ease";
button.style.backdropFilter = "blur(15px) saturate(1.2)";
button.style.webkitBackdropFilter = "blur(15px) saturate(1.2)";
button.style.userSelect = "none";
button.style.zIndex = "999999999999";
button.addEventListener('mouseover', mouseover);
button.addEventListener('mouseout', mouseout);
button.addEventListener('mousedown', dragStart, false);
function mouseover() {
button.style.boxShadow = "0 0 20px rgba(128, 128, 128, 0.8)";
button.style.background = "rgba(160, 160, 160, 0.8)";
button.style.color = "#fff";
button.style.border = "2px solid rgba(200, 200, 200, 1)";
button.style.backdropFilter = "blur(20px) saturate(1.5)";
button.style.webkitBackdropFilter = "blur(20px) saturate(1.5)";
button.innerText = "图片显隐";
button.style.transform = "translateX(0px)";
setTranslate(0+"%",currentY+"px",button);
}
function mouseout() {
button.style.boxShadow = '';
button.style.background = "rgba(128, 128, 128, 0.3)";
button.style.color = "#555";
button.style.border = "2px solid rgba(128, 128, 128, 0.6)";
button.style.backdropFilter = "blur(15px) saturate(1.2)";
button.style.webkitBackdropFilter = "blur(15px) saturate(1.2)";
button.innerText = "◀";
button.style.transform = "translateX(30%)";
setTranslate(30+"%",currentY+"px",button);
}
function dragStart(e) {
startTime = e.timeStamp;
initialX = e.clientX;
initialY = e.clientY - yOffset;
document.addEventListener('mousemove', drag);
document.addEventListener('mouseup', dragEnd, false);
e.preventDefault();
randomNumSet = Math.round(Math.random()*(yanEmoji.length-1));
}
function dragEnd(e) {
if (startTime) {
let diffTime = e.timeStamp - startTime;
diffTime < 150 && handleButtonClick();
startTime = 0;
}
initialX = currentX;
initialY = currentY;
mouseout();
document.removeEventListener('mousemove', drag);
}
function drag(e) {
changeFace(randomNumSet,button);
button.style.color = "#fff";
button.style.border = "4px dashed rgba(128, 128, 128, 0.8)";
button.style.background = "rgba(100, 100, 100, 0.6)";
button.style.backdropFilter = "blur(25px) saturate(1.8)";
button.style.webkitBackdropFilter = "blur(25px) saturate(1.8)";
e.preventDefault();
currentX = e.clientX - initialX;
currentY = e.clientY - initialY;
xOffset = currentX;
yOffset = currentY;
setTranslate(currentX+"px", currentY+"px", button);
}
function setTranslate(xPos, yPos, el) {
el.style.transform = "translate3d(" + xPos + ", " + yPos + ", 0)";
}
function changeFace(randomNum,el) {
el.innerText = yanEmoji[randomNum];
}
document.body.appendChild(button);
})();