0

我正在发现 Raphael JS,我有一个关于在 for 循环中生成的元素上应用鼠标事件的问题。

这是一个打印 5 个矩形的示例代码:

var paper = Raphael("canvasTest",200,200);
for(var i = 0 ; i < 5 ; i++){
    var rect = paper.rect((i*15)+5,10,10,10);
    rect.attr("fill","blue");
    rect.hover(
        function(){
            rect.attr("fill","red");
            document.getElementById("info").innerHTML="Hovered: "+i;
        }, 
        function(){
           rect.attr("fill","blue");
        }
    );
}

这会生成以下输出:

输出

问题是只有第 5 个矩形变成红色(即使另一个矩形悬停),并且infodiv 总是打印第 5 个矩形悬停:

只有第 5 个矩形是红色的。

我发现我可以this在内部函数内部使用它并部分解决了问题。上面的代码将正确的矩形涂成红色,但信息容器仍然打印出第 5 个矩形悬停。

rect.hover(
    function(){
        this.attr("color","red");
        ...
    },
    ...
);

解决这个问题的最干净的方法是什么?我正在考虑为rect诸如设置自定义字段rect.someVariable=i,然后在内部函数中引用它。但也许有更清洁的东西?

在此先感谢您的帮助。

4

2 回答 2

3

在大多数情况下,我建议使用 Chris Wilson 的任何一种技术,但是有一种变体可以实现相同的目标,而不会用实用函数的 debri 字段污染您当前的命名空间。简单地说,与其使用正式定义的函数创建闭包,不如在循环中使用匿名函数创建闭包:

for(var i = 0 ; i < 5 ; i++) {
    var rect = paper.rect((i*15)+5,10,10,10);
    rect.attr("fill","blue");
    ( function( rect, i ) {
        rect.hover(
            function() {
                rect.attr("fill","red");
                document.getElementById("info").innerHTML="Hovered: "+i;
            }, 
            function() {
                rect.attr("fill","blue");
            }
        ); } )( rect, i );
} 

这样的构造只是将循环变量的特定实例嵌入i到在 for 循环的约束中创建的闭包中。十分简单。

于 2013-02-21T18:40:32.663 回答
3

“不要在循环中创建函数”在 Javascript 中相当于棒球中的“不要在第三个或第三个出局”:您可以违反它,但前提是您有充分的理由。你没有。所以你应该关闭:

var paper = Raphael("canvasTest",200,200);

var mybox = function(i) {
    var rect = paper.rect((i*15)+5,10,10,10);
    rect.attr("fill","blue");
    rect.hover(
        function(){
            this.attr("fill","red");
            document.getElementById("info").innerHTML="Hovered: "+i;
        }, 
        function(){
           this.attr("fill","blue");
        } 
    );
    return {
        get_rect: function() { return rect; }
    };
};

for(var i = 0 ; i < 5 ; i++){
    mybox(i);
}

jsFiddle

Doug Crockford 的“Javascript: The Good Parts”是了解原因的最佳起点。如果您出于某种原因真的不想这样做,您还可以使用 Raphael 的 .data() 方法创建对象的 ia 属性:

var paper = Raphael("canvasTest",200,200);
for(var i = 0 ; i < 5 ; i++){
    var rect = paper.rect((i*15)+5,10,10,10);
    rect.data("myindex", i + 1);
    rect.attr("fill","blue");
    rect.hover(
        function(){
            this.attr("fill","red");
            document.getElementById("info").innerHTML="Hovered: " + this.data("myindex");
        }, 
        function(){
           this.attr("fill","blue");
        }
    );
}

我强烈推荐第一种方式。

于 2013-02-20T15:17:04.993 回答