脚本可在浏览器控制台运行但无法在Greasemonkey/Tampermonkey执行求助
问题描述
- 一段颜色替换代码在浏览器控制台执行完全正常,但在Greasemonkey和Tampermonkey中均无法运行
- 未收到脚本或工具的任何报错提示
- 简单
alert语句可正常触发,排除脚本加载失败问题 - 尝试过
waitForKeyElements方法,无效果 - 目标网站:
https://*.robertsspaceindustries.com/spectrum/community/SC/forum/*
原脚本代码:
// ==UserScript== // @name name // @description description // @version 1 // @author me // @match https://*.robertsspaceindustries.com/spectrum/community/SC/forum/* // @icon https://i.imgur.com/km9uoYJ.png // ==/UserScript== function hexToRgb(hex) { // Expand shorthand form (e.g. "03F") to full form (e.g. "0033FF") var shorthandRegex = /^#?([a-f\d])([a-f\d])([a-f\d])$/i; hex = hex.replace(shorthandRegex, function(r, g, b) { return r + r + g + g + b + b; }); var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex); return result ? "rgb(" + [ parseInt(result[1], 16), parseInt(result[2], 16), parseInt(result[3], 16) ].join(', ') + ")" : null; } // Function to change a color to another one function colorChange(colorOld, colorNew, strict = false) { // If hex notation, convert to rgb if (colorOld.includes('#')) colorOld = hexToRgb(colorOld); // Loop through all elements styles [...document.getElementsByTagName('*')].forEach(elm => { let cStyle = getComputedStyle(elm); [...cStyle].forEach(prop => { // Escape if not a string if (typeof cStyle[prop] !== 'string') return; // Check if colorOld is in property if (cStyle[prop].includes(colorOld)){ // If strict, colorOld is replaced only if it's the only value of the property if (!strict || cStyle[prop] === colorOld) elm.style[prop] = cStyle[prop].replace(colorOld, colorNew); // Replace color } }) }) }; colorChange('#182436', '#ff0000');
问题原因与解决办法
核心原因
- 脚本执行时机过早:页面动态加载的元素还未渲染完成,脚本已执行完毕
- 颜色格式匹配不兼容:
getComputedStyle返回的颜色可能是RGBa格式,或存在空格差异(如rgb(24,36,54)vsrgb(24, 36, 54)),导致匹配失败 - 样式优先级被覆盖:脚本设置的行内样式可能被页面自带的高优先级CSS(如
!important规则)覆盖
具体修复方案
1. 延迟脚本执行时机
在脚本元信息中添加@run-at document-idle,确保脚本在页面完全加载后执行:
// ==UserScript== // ... 原有元信息 ... // @run-at document-idle // ==/UserScript==
或用DOMContentLoaded事件包裹执行逻辑:
document.addEventListener('DOMContentLoaded', function() { colorChange('#182436', '#ff0000'); console.log('颜色替换已执行'); });
2. 优化颜色匹配逻辑
修改hexToRgb和颜色匹配逻辑,兼容RGBa格式和空格差异:
function hexToRgb(hex, includeAlpha = false) { const shorthandRegex = /^#?([a-f\d])([a-f\d])([a-f\d])$/i; hex = hex.replace(shorthandRegex, (r, g, b) => r + r + g + g + b + b); const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})?$/i.exec(hex); if (!result) return null; const rgbVals = [ parseInt(result[1], 16), parseInt(result[2], 16), parseInt(result[3], 16) ]; if (includeAlpha && result[4]) { const alpha = parseInt(result[4], 16) / 255; return `rgba(${rgbVals.join(', ')}, ${alpha})`; } return `rgb(${rgbVals.join(', ')})`; } // 统一格式匹配,支持RGB/RGBa、有无空格的情况 function matchesColor(computedColor, targetColor) { const cleanComputed = computedColor.replace(/\s+/g, ''); const cleanTarget = targetColor.replace(/\s+/g, ''); return cleanComputed === cleanTarget || cleanComputed === `${cleanTarget},1`; } function colorChange(colorOld, colorNew, strict = false) { let targetColors = [colorOld]; // 十六进制颜色生成RGB和RGBa两种匹配格式 if (colorOld.includes('#')) { const rgb = hexToRgb(colorOld); const rgba = hexToRgb(colorOld, true); targetColors = [rgb, rgba]; } [...document.querySelectorAll('*')].forEach(elm => { const cStyle = getComputedStyle(elm); [...cStyle].forEach(prop => { if (typeof cStyle[prop] !== 'string') return; targetColors.forEach(target => { if (matchesColor(cStyle[prop], target)) { if (!strict || matchesColor(cStyle[prop], target)) { // 直接设置目标颜色,若被覆盖可添加!important // elm.style.setProperty(prop, colorNew, 'important'); elm.style[prop] = colorNew; } } }); }); }); }
3. 监听动态DOM变化
如果页面是单页应用(SPA),内容会动态更新,需用MutationObserver监听DOM变化:
function setupColorObserver() { const observer = new MutationObserver(() => { colorChange('#182436', '#ff0000'); }); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); } document.addEventListener('DOMContentLoaded', setupColorObserver);
4. 调试技巧
在colorChange函数中添加日志,确认是否匹配到目标元素:
if (matchesColor(cStyle[prop], target)) { console.log('匹配到元素:', elm, '属性:', prop, '原值:', cStyle[prop]); // ... 替换逻辑 ... }
内容的提问来源于stack exchange,提问作者Forceflow
相关产品推荐
相关产品推荐

