Greasy Fork is available in English.
脚本菜单支持多种护眼模式切换,背景与链接颜色配套,支持自定义域名禁用。
// ==UserScript==
// @name 多模式护眼助手
// @version 5.0
// @description 脚本菜单支持多种护眼模式切换,背景与链接颜色配套,支持自定义域名禁用。
// @author Gemini
// @run-at document-start
// @match *://*/*
// @grant GM_registerMenuCommand
// @grant GM_setValue
// @grant GM_getValue
// @namespace http://greasyfork.icu/users/452911
// ==/UserScript==
(function() {
'use strict';
// 1. 配置中心:颜色配套方案
const THEMES = {
'default': { name: '豆沙绿', bg: '#C7EDCC', link: '#2E7D32' },
'parchment': { name: '羊皮纸', bg: '#F4ECD8', link: '#8B4513' },
'pink': { name: '樱花粉', bg: '#FDE2E4', link: '#C2185B' },
'cyan': { name: '青草蓝', bg: '#DCEFF0', link: '#006064' },
'warm': { name: '暖阳黄', bg: '#FAF9DE', link: '#E65100' }
};
let currentMode = GM_getValue('currentMode', 'default');
const currentDomain = window.location.hostname;
let disabledDomains = GM_getValue('disabledDomains', []);
let isDisabled = disabledDomains.includes(currentDomain);
// 2. 注入动态 CSS 变量控制中心
const styleEl = document.createElement('style');
styleEl.id = 'eye-protector-core-style';
// 在 head 还没加载出来时,注入到 documentElement
(document.head || document.documentElement).appendChild(styleEl);
function updateCSSVars(modeKey) {
if (isDisabled) {
styleEl.textContent = '';
return;
}
const theme = THEMES[modeKey] || THEMES.default;
styleEl.textContent = `
:root {
--eye-bg: ${theme.bg} !important;
--eye-link: ${theme.link} !important;
}
/* 只有被打上标记的元素才会变色 */
[data-eye-bg="true"] { background-color: var(--eye-bg) !important; background-image: none !important; }
[data-eye-link="true"] { color: var(--eye-link) !important; text-decoration: none !important; }
`;
}
// 3. 元素扫描与标记引擎
function scanAndTag() {
if (isDisabled) return;
// 获取所有尚未被本脚本扫描过的元素
const elements = document.querySelectorAll('*:not([data-eye-scanned])');
elements.forEach(el => {
el.setAttribute('data-eye-scanned', 'true');
// A. 排除项:视频、图片、画板、图标
if (el.matches('video, img, canvas, svg, [class*="player"], .icon, .fa')) return;
// B. 链接处理
if (el.tagName === 'A') {
el.setAttribute('data-eye-link', 'true');
}
// C. 背景处理:针对原脚本提到的特殊 ID 和 类名 进行强制覆盖
if (el.matches('DIV#gb-main, DIV.url.clearfix, DIV.nav-bar-v2-fixed, DIV.se-page-hd-content')) {
el.setAttribute('data-eye-bg', 'true');
return;
}
// D. 智能背景判定:如果是浅色背景,则标记
const style = window.getComputedStyle(el);
const bgColor = style.backgroundColor;
const rgb = bgColor.match(/\d+/g);
if (rgb && rgb.length >= 3) {
const [r, g, b] = rgb.map(Number);
// 判定阈值:RGB 均大于 220 通常为白色或近白色背景
if (r > 220 && g > 220 && b > 220) {
el.setAttribute('data-eye-bg', 'true');
}
}
});
}
// 4. 注册脚本菜单
function initMenus() {
// 开关切换
GM_registerMenuCommand(isDisabled ? "🟢 开启当前网站护眼" : "🔴 禁用当前网站护眼", () => {
if (isDisabled) {
disabledDomains = disabledDomains.filter(d => d !== currentDomain);
} else {
disabledDomains.push(currentDomain);
}
GM_setValue('disabledDomains', disabledDomains);
location.reload(); // 涉及域名白名单,建议刷新以重置所有样式
});
// 颜色模式切换(无需刷新)
Object.keys(THEMES).forEach(key => {
GM_registerMenuCommand("🎨 模式:" + THEMES[key].name, () => {
currentMode = key;
GM_setValue('currentMode', key);
updateCSSVars(key);
console.log(`已切换至: ${THEMES[key].name}`);
});
});
}
// 5. 启动逻辑
updateCSSVars(currentMode);
initMenus();
// 持续监听:处理动态加载、瀑布流、弹窗等新元素
const observer = new MutationObserver(() => {
scanAndTag();
});
// 监听文档变化
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', () => {
observer.observe(document.body, { childList: true, subtree: true });
scanAndTag();
});
} else {
observer.observe(document.body, { childList: true, subtree: true });
scanAndTag();
}
// 兜底:处理某些特殊加载情况
window.addEventListener('load', scanAndTag);
})();