我正在尝试编写一个隐藏IMDb评级的跨浏览器用户脚本,并将其替换为允许用户稍后对该节目/电影进行评级的链接。
在Opera中,这种方法已经有效,但Firefox和Chrome都发现了一个未定义的函数和/或变量。这是我目前的代码:
function hideimdbratings() {
if (document.getElementsByClassName("star-box")[0]) {
reenabled = document.getElementsByClassName("star-box")[0].innerHTML;
document.getElementsByClassName("star-box")[0].innerHTML = '<a href="#" id="showvote" onclick="reenableit();">Rate!</a>';
}
}
function reenableit() {
document.getElementsByClassName("star-box")[0].innerHTML = reenabled;
}
window.addEventListener('load', hideimdbratings, false);
第一部分工作正常,hideimdbratings()
被执行并隐藏评级。
但是,点击“评价!”链接后,Firefox和Chrome都会说reenableit()
未定义。
试试这个:
onclick="document.getElementsByClassName(\"star-box\")[0].innerHTML = reenabled;"
结果是reenabled
未定义。
我尝试将代码直接放入事件监听器:
window.addEventListener("load", function(e) {
// ...
}, false);
这种定义函数的方法(使用Firefox的unsafeWindow):
var window.reenableit = function() { }
但是,无论我做什么,reenableit()
和reenabled
都未定义。根据我的理解,除了Opera之外,函数和变量都不是全局的,但我似乎还没有找到解决方案。
我错过了什么/做错了什么?
答案 0 :(得分:1)
我无法弄清楚如何使变量或函数全局化,虽然这是一个解决方案应该适合你:
function hideimdbratings() {
if (document.getElementsByClassName('star-box')[0]) {
// hide the "star-box" container
var b = document.getElementsByClassName('star-box')[0];
b.style.display = 'none';
// add the "Rate!" link
var n = document.createElement('a');
n.setAttribute('href', 'javascript:void(0);');
n.setAttribute('onclick', 'document.getElementsByClassName("star-box")[0].style.display = "block"; this.style.display = "none";');
n.innerHTML = 'Rate!';
b.parentNode.insertBefore(n, b.nextSibling);
}
}
window.addEventListener('load', hideimdbratings, false);
答案 1 :(得分:1)
该代码无法在Chrome中使用,因为Chrome用户脚本在沙箱中运行("isolated world"),您无法在Chrome中设置或使用页面范围的javascript对象。而且,Chrome无法完全/正确支持unsafeWindow
。
代码将在Firefox + Greasemonkey中工作并谨慎使用unsafeWindow
,但这里不建议这样做(并且对Chrome没有帮助)。
经典方法,当需要以跨浏览器方式与页面范围javascript交互时,使用Script Injection。这是唯一适用于Chrome的功能。
然而,最明智的做法就是不使用页面范围JS,如果你不需要的话。并且,对于这个问题中的内容,您不需要。 (提示:永远不要使用onclick
或类似属性!始终使用addEventListener()
或同等属性。)
重构代码以避免离开沙箱范围,它变为:
function hideImdbRatings () {
var oldStarBoxHTML;
var starBox = document.getElementsByClassName ("star-box");
if (starBox.length) {
starBox = starBox[0];
oldStarBoxHTML = starBox.innerHTML;
starBox.innerHTML = '<a href="#" id="showVote">Rate!</a>';
document.getElementById ("showVote").addEventListener (
"click",
function () {
//-- "this" is a special javascript scope.
this.innerHTML = oldStarBoxHTML;
}
);
}
}
window.addEventListener ('load', hideImdbRatings, false);
但是2 ,您会注意到目前为止 所有 代码,破坏了IMDB评级小部件的互动。这是因为它覆盖了innerHTML
,它会破坏小部件的事件处理程序。不要那样使用innerHTML
。
最明智的做法是隐藏块,类似于Geo的回答,如下:
function hideImdbRatings () {
var starBox = document.getElementsByClassName ("star-box");
if (starBox.length) {
starBox = starBox[0];
starBox.style.display = 'none';
var rateLink = document.createElement ('a');
rateLink.id = 'showVote';
rateLink.href = '#';
rateLink.textContent = 'Rate!';
starBox.parentNode.insertBefore (rateLink, starBox);
document.getElementById ("showVote").addEventListener (
"click",
function () {
//-- "this" is a special javascript scope.
this.style.display = 'none';
starBox.style.display = 'block';
}
);
}
}
window.addEventListener ('load', hideImdbRatings, false);
还有可能会阻止脚本在Chrome中运行的其他因素。 By default, Chrome userscripts may run after the load
event.要解决此问题,请在脚本the metadata block中指定@run-at document-end
答案 2 :(得分:0)
啊哈!找到了。试试这个:
var uw = (this.unsafeWindow) ? this.unsafeWindow : window;
var b = document.getElementsByClassName('star-box')[0];
uw.reenabled = b.innerHTML;
b.innerHTML = '<a href="javascript:void(0);" onclick="document.getElementsByClassName(\'star-box\')[0].innerHTML = reenabled;">Rate!</a>';
受this post启发