Raphael JS for循环中的鼠标事件

时间:2013-02-20 08:12:00

标签: javascript canvas raphael mouseevent

我正在发现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");
        }
    );
}

这会生成以下输出:

Output

问题是只有第5个矩形变为红色(即使另一个变为红色),info div总是打印出第五个矩形悬停:

Only the 5th rectangle is colored in red.

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

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

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

提前感谢您的帮助。

2 个答案:

答案 0 :(得分: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()方法使我成为该对象的属性:

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");
        }
    );
}

我强烈推荐第一种方式。

答案 1 :(得分: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循环的约束内创建的闭包中。容易,轻松。