Javascript onclick方法在我声明它时执行

Javascript onclick方法在我声明它时执行,javascript,raphael,Javascript,Raphael,我试图声明一个onclick方法,该方法将调用一个函数,该函数用于清除并重建显示所单击项目的更多详细信息的显示。问题是我试图分配的onclick方法在分配时执行,因此我看到的只是其中一个项目的详细视图 如果删除i.node.onclick行,您将看到5个随机放置的项目,您可以将其悬停在上面,但不能单击 HTML 拉斐尔戏剧 #地图 { 宽度:500px; 边框:1px实心#aaa; } JavaScript var map; var items = new Array(); win

我试图声明一个
onclick
方法,该方法将调用一个函数,该函数用于清除并重建显示所单击项目的更多详细信息的显示。问题是我试图分配的
onclick
方法在分配时执行,因此我看到的只是其中一个项目的详细视图

如果删除
i.node.onclick
行,您将看到5个随机放置的项目,您可以将其悬停在上面,但不能单击

HTML


拉斐尔戏剧
#地图
{  
宽度:500px;
边框:1px实心#aaa;
}  
JavaScript

var map;
var items = new Array();

window.onload = function() 
{  
   map = new Raphael(document.getElementById('map'), 500, 500);  

   for(cnt = 0; cnt < 5; cnt++)
   {
      var x = 5 + Math.floor(Math.random() * 490);
      var y = 5 + Math.floor(Math.random() * 490);

      items[cnt] = new Item(x, y);

      var i = map.circle(items[cnt].x, items[cnt].y, 8).attr({fill: "#000", stroke: "#f00", title: items[cnt].name}); 
      i.node.onclick = detailView(items[cnt]);
   }
} 

function Item(x, y)
{
   this.x = x;
   this.y = y;
   this.name = "Item[" + x + "," + y + "]";
}

function detailView(dv)
{
   map.clear();

   map.circle(250, 250, 25).attr({fill: "#0f0", stroke: "#f00", title: dv.name});
}
var映射;
var items=新数组();
window.onload=函数()
{  
map=newRaphael(document.getElementById('map'),500500);
对于(cnt=0;cnt<5;cnt++)
{
var x=5+数学地板(数学随机()*490);
变量y=5+Math.floor(Math.random()*490);
项目[cnt]=新项目(x,y);
var i=map.circle(items[cnt].x,items[cnt].y,8).attr({fill:#000),stroke:#f00,title:items[cnt].name});
i、 node.onclick=detailView(items[cnt]);
}
} 
功能项(x,y)
{
这个.x=x;
这个。y=y;
this.name=“项目[“+x+”,“+y+”];
}
函数详细视图(dv)
{
map.clear();
圆(250250,25).attr({fill:#0f0),stroke:#f00,title:dv.name});
}

首先,您需要一个助手函数:

  function detailViewer(item) {
    return function() { detailView(item); };
  }
然后将单击处理程序设置为:

  i.node.onclick = detailViewer(items[cnt]);

helper函数生成一个函数,在调用该函数时,该函数将调用“detailView()”函数,并传入与节点相关的项。正如您所注意到的,您编写的代码在执行初始化时只调用了“detailView()”。“onclick”属性本身需要是一个函数,这就是我上面提出的helper函数将为您提供的功能。

首先,您需要一个helper函数:

  function detailViewer(item) {
    return function() { detailView(item); };
  }
然后将单击处理程序设置为:

  i.node.onclick = detailViewer(items[cnt]);

helper函数生成一个函数,在调用该函数时,该函数将调用“detailView()”函数,并传入与节点相关的项。正如您所注意到的,您编写的代码在执行初始化时只调用了“detailView()”。“onclick”属性本身需要是一个函数,这就是我上面提出的helper函数将为您提供的功能。

您需要将
I.node.onclick
设置为一个函数。您将其设置为
detailView(items[cnt])
,该函数运行该函数,然后将
i.node.onclick
设置为返回值(未定义的

您需要让
detailView
返回一个函数

function detailView(dv){
  return function(){
    map.clear();
    map.circle(250, 250, 25).attr({fill: "#0f0", stroke: "#f00", title: dv.name});
  };
}

您需要将
i.node.onclick
设置为函数。您将其设置为
detailView(items[cnt])
,该函数运行该函数,然后将
i.node.onclick
设置为返回值(未定义的

您需要让
detailView
返回一个函数

function detailView(dv){
  return function(){
    map.clear();
    map.circle(250, 250, 25).attr({fill: "#0f0", stroke: "#f00", title: dv.name});
  };
}

另一个选项只是在onclick中声明匿名函数:
i.node.onclick=function(){detailView(items[cnt]);}
@Platinum Azure,在这种情况下不起作用,因为分配是在循环中进行的!啊,我以为分配给不同的节点。我对拉斐尔一无所知,所以我可能错了-((也就是说,它们看起来似乎是等价的,因为您的函数返回的是我的匿名函数…)问题在于变量“cnt”将由所有处理程序共享-该函数中只有一个处理程序,因此每个闭包将引用相同的值。因此,当处理程序实际运行时,“cnt”的值将是错误的!这是JavaScript中的一个经典陷阱,因为只有函数引入新的作用域。您可以“内联”执行此操作通过将函数包装到另一个函数中,来制作“cnt”的副本。感谢您帮助我理解代码不起作用的原因。JavaScript中的变量作用域很棘手…另一个选项只是在onclick中声明匿名函数:
i.node.onclick=function(){detailView(items[cnt]);}
@Platinum Azure在这种情况下不起作用,因为赋值是在循环中进行的!啊,我以为赋值是给不同的节点的。我对Raphael一无所知,所以我可能是错的。:-((也就是说,它们看起来很可疑,因为你的函数返回的是我的匿名函数…)@问题是变量“cnt”将由所有处理程序共享-该函数中只有一个处理程序,因此每个闭包将引用相同的值。因此,当处理程序实际运行时,“cnt”的值这可能是错误的!这是JavaScript中的一个经典陷阱,因为只有函数才会引入新的作用域。您可以通过将函数包装到另一个函数中来实现“内联”,以制作“cnt”的副本。感谢您帮助我理解代码无法运行的原因。JavaScript中的变量作用域很棘手…我喜欢此选项的原因是我少维护一个函数。我喜欢此选项的原因是我少维护一个函数。