我正在发现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个矩形变为红色(即使另一个变为红色),info
div总是打印出第五个矩形悬停:
我发现我可以在内部函数中使用this
,它可以部分解决问题。上面的代码用红色标出正确的矩形,但信息容器仍然打印出第五个矩形悬停。
rect.hover(
function(){
this.attr("color","red");
...
},
...
);
解决这个问题的最简洁方法是什么?我正在考虑为rect
设置自定义字段,例如rect.someVariable=i
,然后在内部函数中引用它。但也许还有更清洁的东西?
提前感谢您的帮助。
答案 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);
}
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循环的约束内创建的闭包中。容易,轻松。