我的 map 上有标记图层。
每次添加新标记时,我都会将其注册到鼠标单击事件中:
var lonlat = new OpenLayers.LonLat(lon,lat);
var marker = new OpenLayers.Marker(lonlat,icon);
marker.id = callId;
marker.events.register("mousedown", marker, function() {AddPopup(marker.id);});
callMarkers.addMarker(marker);
有时我想禁用/启用该事件。所以我使用这些功能:
function EnableAllMarkers()
{
for (var i in callMarkers.markers)
{
callMarkers.markers[i].events.remove("mousedown");
callMarkers.markers[i].events.register("mousedown", callMarkers.markers[i],
function() { AddPopup(callMarkers.markers[i].id); });
}
}
function DisableAllMarkers()
{
for (var i in callMarkers.markers)
{
callMarkers.markers[i].events.remove("mousedown");
}
}
当我使用此代码时,我会遇到奇怪的行为 - 有时会为错误的标记打开一个弹出窗口。
我点击标记 X 并打开弹出窗口 Y。
有人可以帮帮我吗?
注意:
EnableAllmMarkers
首先删除事件的原因是因为我们不知道在添加新标记后是否曾调用过 DisableAllmMarkers
。如果它确实被调用,remove 函数将不执行任何操作。
最佳答案
这是一个典型的 JavaScript 陷阱:您在循环中将函数实例化为事件处理程序,而这些函数引用局部变量。问题是它们所有 都引用相同 局部变量:相同的、单一的、唯一的、在内存中只有一个位置的变量。本例中的变量是“i”。
在 for
循环结束时,“i”将具有对象中最后一个键的值(顺便说一下,如果 callMarkers.markers
确实是一个数组,那么无论如何这都不应该是一个 for ... in
循环,但这是一个单独的问题)。因此,当这些事件最终触发时,所有处理程序都将使用等于同一个键的“i”来执行它们的操作。
修复:
for (var i in callMarkers.markers)
{
callMarkers.markers[i].events.remove("mousedown");
callMarkers.markers[i].events.register(
"mousedown",
callMarkers.markers[i],
(function(ii) {
return function() {
AddPopup(callMarkers.markers[ii].id);
}
)(i)
);
}
这引入了一个中间匿名函数。该函数立即被调用,并传递了“i”的当前值。通过这样做——将“i”作为参数传递给匿名函数——该值在参数“ii”中被“捕获”。每次循环迭代都会导致匿名函数的另一次调用,它返回的函数(实际处理程序)将有权访问它自己的私有(private)“ii”变量。
还有一些其他方法可以实现相同的目的,但它们都只是这个主题的变体。
关于javascript - OpenLayer 中标记事件的奇怪行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4837153/