2

我正在尝试编写一个跨浏览器用户脚本来隐藏 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()执行并隐藏评级。

但是,点击“Rate!”链接后,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 以外的浏览器中都不是全局的,但我似乎还没有找到解决方案。

我错过了什么/做错了什么?

4

3 回答 3

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);
于 2013-01-29T18:52:37.457 回答
1

该代码在 Chrome 中不起作用,因为 Chrome 用户脚本在沙箱(“孤立世界”)中运行,并且您无法在 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 中运行。 默认情况下,Chrome 用户脚本可能会在load事件发生后运行。 要解决此问题,请@run-at document-end在脚本的元数据块中指定。

于 2013-01-30T11:23:28.793 回答
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>';

这篇文章的启发

于 2013-01-29T21:20:47.927 回答